which is more portable than type (FreeBSD).
[wine/wine-kai.git] / tools / winecheck
blob5be63cded69458af0885b0d34e5a9fbc343e0e67
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 # (C) 2001 Andreas Mohr
6 # Redistributable under Wine License
8 # FIXME:
9 # - implement cmdline arguments e.g. for confirmation keypress
10 # in case of a problem
12 # TODO:
13 # - implement it in a much more systematic way. This is a quick hack for now
14 # (like every Perl program ;-)
15 # And much more so since I'm NOT a Perl hacker
16 # - test/tweak on non-Linux systems
19 use Getopt::Long;
20 use strict;
22 my $hold = 0;
24 my $count_tests = 0;
25 my $count_ok = 0;
26 my $count_suspect = 0;
27 my $count_bad = 0;
28 my $count_critical = 0;
29 my $count_failed = 0;
31 my $is_notchecked = 0;
32 my $is_ok = 1;
33 my $is_suspect = 2;
34 my $is_bad = 3;
35 my $is_critical = 4;
36 my $is_failed = 5;
38 my $factor_suspect = 0.995;
39 my $factor_bad = 0.95;
40 my $factor_critical = 0.85;
41 my $factor_failed = 0.15;
43 my $correctness = 100.0;
45 my $indent = 0;
47 my ($level, $reason, $advice);
49 my $advice_chmod = "If your user account is supposed to be able to access
50 it properly, use chmod as root to fix it (\"man chmod\")";
51 my $advice_fs = "The Filesystem option indicates the filesystem behaviour Wine is supposed to *emulate*, not the filesystem which is there";
53 my $dev_read = 1;
54 my $dev_write = 2;
55 my $dev_open = 4;
57 select(STDERR); $| = 1; # make unbuffered
58 select(STDOUT); $| = 1; # make unbuffered
60 #--------------------------------- main program --------------------------------
61 &Introduction();
62 &Check_BaseFiles();
63 &Check_ConfigFile();
64 &Check_Devices();
65 &Check_Registry();
66 &Check_WindowsFiles();
67 &Print_Score();
69 #------------------------------- support functions -----------------------------
70 sub Do_PrintHeader {
71 my ($str) = @_;
72 my $len = length($str);
73 my $num = int((80 - $len - 2)/2);
74 my $i;
76 print "\n";
77 for ($i = 0; $i < $num; $i++) {
78 print "-";
80 print " ".$str." ";
81 for ($i = 0; $i < $num; $i++) {
82 print "-";
84 if ($len % 2)
86 print "-";
88 print "\n";
91 sub Do_Check {
92 my ($text) = @_;
93 my $test_no;
94 my $indent_str = "";
96 $count_tests++;
97 $test_no = sprintf("%03d", $count_tests);
98 for (my $i = 0; $i < $indent; $i++)
100 $indent_str = $indent_str." ";
102 print sprintf("%.60s", $test_no.".".$indent_str." Checking ".$text."... ");
105 sub Do_PrintResult {
106 my($level, $str, $advice, $skip_score) = @_;
107 my $err;
108 my $key;
110 if ($level == $is_notchecked)
112 $err = "NOT CHECKED";
113 $str = "";
114 $advice = "";
116 elsif ($level == $is_ok)
118 $err = "OK";
119 $str = "";
120 $advice = "";
121 $count_ok++;
123 elsif ($level == $is_suspect)
125 $err = "SUSPICIOUS";
126 $count_suspect++;
127 if (! $skip_score)
129 $correctness *= $factor_suspect;
132 elsif ($level == $is_bad)
134 $err = "BAD";
135 $count_bad++;
136 if (! $skip_score)
138 $correctness *= $factor_bad;
141 elsif ($level == $is_critical)
143 $err = "CRITICAL";
144 $count_critical++;
145 if (! $skip_score)
147 $correctness *= $factor_critical;
150 elsif ($level == $is_failed)
152 $err = "FAILED";
153 $count_failed++;
154 if (! $skip_score)
156 $correctness *= $factor_failed;
159 print $err;
160 if ($str)
162 print " (".$str.")";
164 print ".";
165 if ($hold)
167 print " Press Enter.";
168 $key = getc(STDIN);
170 else
172 print "\n";
174 if ($advice)
176 print "- ADVICE: ".$advice.".\n";
180 #-------------------------------- main functions ------------------------------
181 sub Introduction {
182 print "This script verifies the configuration of the whole Wine environment.\n";
183 print "Note that this is an ALPHA version, and thus it doesn't catch all problems !\n";
184 print "The results of the checks are printed on the right side:\n";
185 print "OK - test passed without problems.\n";
186 print "SUSPICIOUS - potentially problematic. You might want to look into that.\n";
187 print "BAD - This is a problem, and it leads to configuration score penalty.\n";
188 print "CRITICAL - A critical problem which can easily lead to malfunction.\n";
189 print "FAILED - This problem leads to Wine failure almost certainly.\n";
190 print "\nThe result will be printed as a percentage score indicating config completeness.\n";
191 print "\n";
192 if ($hold)
194 my $key;
195 print "Press Enter to continue or Ctrl-C to exit.";
196 $key = getc(STDIN);
200 sub Check_BaseFiles {
201 my $line;
203 Do_PrintHeader("checking Wine base files");
205 $level = $is_ok;
206 Do_Check("for file \"wine\"");
207 $line = `which wine`;
208 if (!$line)
210 $level = $is_failed;
211 $reason = "file not found";
212 $advice = "Make sure the \"wine\" command is in your PATH (echo \$PATH; export PATH=xxx)";
214 Do_PrintResult($level, $reason, $advice);
216 # check for config mess
217 $level = $is_ok;
218 my @output = ();
219 Do_Check("for correct .so lib config (please wait)");
221 # Build list of library directories.
222 # First parse ld.so.conf to find system-wide lib directories.
223 my @dirlist = ();
224 open (LDCONF, "</etc/ld.so.conf");
225 while (<LDCONF>) {
226 s/\#.*//; # eliminate comments
227 chomp;
228 if (-d $_) { push @dirlist, $_; }
230 close (LDCONF);
231 # Next parse LD_LIBRARY_PATH to find user-specific lib dirs.
232 my (@ld_dirs) = split (/:/, $ENV{'LD_LIBRARY_PATH'});
233 my ($dir);
234 foreach $dir (@ld_dirs) {
235 if (-d $dir) { push @dirlist, $dir; }
238 # Now check for a libwine.so in each directory
239 foreach $dir (@dirlist) {
240 my ($target) = $dir . "/libwine.so";
241 if (-f $target) { push @output, $target; }
243 print "DEBUG: found libwine: @output\n";
245 if (@output > 1)
247 $level = $is_suspect;
248 my $dirs = "";
249 foreach $line (@output) {
250 chomp $line;
251 $dirs = $dirs." ".$line;
253 $reason = "libwine.so found ".@output." times:".$dirs;
254 $advice = "check whether this is really ok";
256 Do_PrintResult($level, $reason, $advice);
259 sub Do_Config_Drive {
260 my ($drive, $entries, $values) = @_;
261 my $index = 0;
262 my $arg;
263 my $path = "";
264 my $type = "";
265 my $label = "";
266 my $serial = "";
267 my $device = "";
268 my $fs = "";
269 my $unknown = "";
270 my $level;
271 my $my_advice_fat = "If that doesn't help, change mount options in case of VFAT (\"umask\" option)";
273 print "\n>>> Checking drive ".$drive." settings:\n";
274 $reason = "";
275 while (@$entries[$index])
277 $arg = @$values[$index];
278 SWITCH: for (@$entries[$index]) {
279 /^path$/i && do { $path = $arg; last; };
280 /^type$/i && do { $type = $arg; last; };
281 /^label$/i && do { $label = $arg; last; };
282 /^serial$/i && do { $serial = $arg; last; };
283 /^device$/i && do { $device = $arg; last; };
284 /^filesystem$/i && do { $fs = $arg; last; };
285 $unknown = @$entries[$index];
287 $index++;
290 $indent++;
292 my $serious = ($drive =~ /^C$/i) || ($type =~ /^cdrom$/i);
294 ##### check Path #####
295 Do_Check("Path option");
296 $level = $is_ok;
297 $advice = "The syntax of the Path option has to be something like /my/mount/point";
298 if (! $path)
300 $level = $serious ? $is_failed : $is_bad;
301 $reason = "no Path option given in config file";
303 elsif ($path =~ /\\/)
305 $level = $serious ? $is_failed : $is_bad;
306 $reason = "wrong Path format ".$path;
308 elsif ($path =~ /\$\{(.*)\}$/)
310 # get path assigned to environment variable
311 my $envpath = $ENV{$1};
312 if (! $envpath)
314 $level = $serious ? $is_failed : $is_critical;
315 $reason = "Path \"".$path."\" references environment variable \"".$1."\" which is undefined";
316 $advice = "set environment variable before starting Wine or give a \"real\" directory instead";
318 else
320 $path = $envpath;
321 goto PERMCHECK; # hmpf
324 else
326 PERMCHECK:
327 if (!-e $path)
329 $level = $serious ? $is_failed : $is_suspect;
330 $reason = $path." does not exist !";
331 $advice = "create this directory or point Path to a real directory";
333 elsif (!-r $path)
335 $level = $serious ? $is_failed : $is_bad;
336 $reason = $path." is not readable for you";
337 $advice = $advice_chmod.". ".$my_advice_fat;
339 elsif ((! ($type =~ /^cdrom$/i)) && (!-w $path))
341 $level = ($drive =~ /^C$/i) ? $is_failed : $is_suspect;
342 $reason = $path." is not writable for you";
343 $advice = $advice_chmod.". ".$my_advice_fat;
345 else # check permissions of the drive's directories
347 my(@output) = ();
348 push (@output, `find $path 2>&1 1>/dev/null`);
349 foreach my $line (@output) {
350 if ($line =~ /find:\ (.*):\ Permission denied$/)
352 $level = ($drive =~ /^C$/i) ? $is_critical : $is_suspect;
353 $reason = "directory $1 is not accessible for you";
354 $advice = $advice_chmod.". ".$my_advice_fat;
355 last;
360 Do_PrintResult($level, $reason, $advice);
362 ##### check Type #####
363 if ($type)
365 Do_Check("Type option");
366 $level = $is_ok;
367 SWITCH: for ($type) {
368 /^floppy$/i && do { last; };
369 /^hd$/i && do { last; };
370 /^network$/i && do { last; };
371 /^cdrom$/i && do {
372 if (! $device)
374 $level = $is_critical;
375 $reason = "no Device option found -> CD-ROM labels can''t be read";
376 $advice = "add Device option and make sure the device given is accessible by you";
378 last;
380 /^ramdisk$/i && do { last; };
381 if ($type)
383 $level = $is_bad;
384 $reason = "invalid Type setting ".$type;
385 $advice = "use one of \"floppy\", \"hd\", \"network\" or \"cdrom\"";
388 Do_PrintResult($level, $reason, $advice);
391 ##### FIXME: check Label and Serial here #####
393 ##### check Device #####
394 if ($device)
396 my $mode = ($type =~ /^cdrom$/i) ? $dev_read : $dev_read|$dev_write;
397 &Do_CheckDevice("device", $device, 1, $mode);
400 ##### check Filesystem #####
401 if ($fs)
403 Do_Check("Filesystem option");
404 $level = $is_ok;
405 SWITCH: for ($fs) {
406 /^(dos|fat|msdos|unix)$/i && do {
407 $level = $is_bad;
408 $reason = "You probably don't want to use \"".$fs."\". ".$advice_fs;
409 if ($fs =~ /^unix$/i)
411 $advice = "This should almost never be used";
413 else
415 $advice = "only use ".$fs." if you only have a crappy 8.3 filename (i.e.: non-LFN) DOS FAT kernel filesystem driver";
417 last;
419 /^vfat$/i && do { last; };
420 /^win95$/i && do { last; };
421 if ($fs)
423 $level = $is_bad;
424 $reason = "invalid Filesystem setting ".$type;
425 $advice = "use one of \"win95\", \"msdos\" or \"unix\"";
428 Do_PrintResult($level, $reason, $advice);
430 $indent--;
431 if ($reason) {
432 print "--> PROBLEM.\n";
434 else
436 print "--> OK.\n";
440 sub Do_Config_Main {
441 my ($file) = shift;
442 my ($config, $line);
443 my $section = "";
444 my (@entries, @values);
445 LINE: while (<$file>)
447 $line = $_;
448 next LINE if ($line =~ /[\ ]*[;#]/); # skip comments
449 chomp $line;
450 #print "line: ".$line."\n";
451 if ($line =~ /\[(.*)\]/) # end of section/next section ?
453 my $nextsection = $1;
454 my $found = 1;
455 SWITCH: for ($section) {
456 /Drive\ (.)/i && do { &Do_Config_Drive($1, \@entries, \@values); last; };
457 if ($section)
459 $found = 0;
462 $section = $found ? $nextsection : "";
463 @entries = (); @values = ();
464 next LINE;
466 if ($line =~ /^[\ \t]*\"(.*)\"[\ \t]*\=[\ \t]*\"(.*)\"/)
468 push(@entries, $1);
469 push(@values, $2);
474 sub Check_ConfigFile {
475 my $config = "$ENV{'HOME'}/.wine/config";
476 my $indrive = 0;
478 Do_PrintHeader("checking config file");
480 Do_Check("config file access");
481 open(CFGFILE, $config);
482 if (! <CFGFILE>)
484 if (!-e $config) {
485 $reason = $config." does not exist";
486 $advice = "it is ok in case you have ~/.winerc. If you don''t, then you''re in trouble !";
488 elsif (!-r $config) {
489 $reason = $config." not readable";
490 $advice = $advice_chmod;
492 Do_PrintResult($is_failed, $reason, $advice);
493 return;
495 if (!-w $config)
497 Do_PrintResult($is_failed, $config." not writable", "wineserver needs to be able to write to config file. ".$advice_chmod);
499 else
501 Do_PrintResult($is_ok);
503 Do_Config_Main(\*CFGFILE);
504 close(CFGFILE);
507 sub Do_CheckDevice {
508 my($descr, $dev, $output, $mode) = @_;
509 my $level = $is_ok;
510 my $errstr = "";
512 if (! $mode)
514 $mode = $dev_read|$dev_write|$dev_open;
516 ($output != -1) && Do_Check($descr." ".$dev);
518 my $err_level = ($output == 1) ? $is_critical : $is_bad;
520 if (!-e $dev)
522 $level = $err_level;
523 $reason = $dev." does not exist";
524 $advice = "use MAKEDEV script to create it";
525 goto FAILED;
527 if (($mode & $dev_read) && (!-r $dev))
529 $level = $err_level;
530 $reason = $dev." is not readable for you";
531 $advice = $advice_chmod;
532 goto FAILED;
534 if (($mode & $dev_write) && (!-w $dev))
536 $level = $err_level;
537 $reason = $dev." is not writable for you";
538 $advice = $advice_chmod;
539 goto FAILED;
541 if (($mode & $dev_open) && (!open(DEVICE, ">$dev")))
543 $level = $err_level;
544 $reason = "no kernel driver for ".$dev."?";
545 $advice = "module loading problems ? Read /usr/src/linux/Documentation/modules.txt";
546 goto FAILED;
549 FAILED:
550 close(DEVICE);
551 ($output != -1) && Do_PrintResult($level, $reason, $advice);
554 sub Check_Devices {
555 # FIXME: check joystick and scsi devices !
556 my $dev_sound = "/dev/dsp";
557 my $dev_mixer = "/dev/mixer";
558 my $dev_sequencer = "/dev/sequencer";
559 my $dev_mem = "/dev/mem";
561 Do_PrintHeader("checking system devices used by Wine");
562 &Do_CheckDevice("sound device", $dev_sound, 1);
563 &Do_CheckDevice("audio mixer device", $dev_mixer, 1);
564 &Do_CheckDevice("MIDI sequencer device", $dev_sequencer, 0);
567 sub Check_Registry {
568 my(@entries) = ();
569 my $regfile = $ENV{'HOME'}."/.wine/system.reg";
571 Do_PrintHeader("checking registry configuration");
573 Do_Check("availability of winedefault.reg entries");
574 push (@entries, `grep "SHAREDMEMLOCATION" $regfile`);
575 if (@entries)
577 Do_PrintResult($is_ok);
579 else
581 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");
583 @entries = ();
585 Do_Check("availability of windows registry entries");
586 # FIXME: use a different key for check if Wine adds this one to its
587 # default registry.
588 push (@entries, `grep "Default Taskbar" $regfile`);
589 if (@entries)
591 Do_PrintResult($is_ok);
593 else
595 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. Original registry entries won't be available with a no-windows install, of course, so you'll have to live with that.");
597 @entries = ();
600 sub Check_WindowsFiles {
603 sub Print_Score {
604 # my ($score_total, $score_reached, $score_percent);
606 # $score_total = $count_tests * 20;
607 # $score_reached = $count_ok * 20 +
608 # $count_bad * 15 +
609 # $count_critical * 5 +
610 # $count_failed * 0;
611 # $score_percent = $score_reached * 100 / $score_total;
613 print "\n";
614 print $count_tests." tests. ".$count_suspect." suspicious, ".$count_bad." bad, ".$count_critical." critical, ".$count_failed." failed.\n";
615 print sprintf "Wine configuration correctness score: %2.2f%%\n", $correctness;