3 # This program generates wine.conf files on STDOUT.
4 # Copyright (C) 1996 Stephen Simmons
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # This library 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 GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 # This program examines the contents of the DOS filesystems and
23 # attempts to generate a sensible wine.conf file. This is output
25 # It reads /etc/fstab to find mounting locations of the hard disk drives
26 # It uses the correct algorithm for ordering DOS drives, with the
27 # exception of the case of multiple drive controller types, where I don't
28 # know what DOS's algorithm is.
29 # It uses find to find all of the win.ini files on any DOS partition
30 # and sorts them by age to guess which is part of the active Windows
32 # It reads the autoexec.bat file (if found) and records all variable
33 # settings. There are some inaccuracies in its determination.
34 # First, while variables are interpolated properly, no control
35 # structures are supported so calls and execs to other batch files are
36 # ignored, and all variable settings take effect regardless of whether
37 # they would in DOS (i,e., both if and else clauses are read).
38 # This is used to determine the path and temp directories. Duplicate
39 # path directories and path directories that don't exist are thrown
41 # On failing to find C:\AUTOEXEC.BAT, wineconf finds all executables
42 # in the windows directory and subdirectories, and generates an
43 # optimized path statement encompassing all the executables.
44 # Then it also looks for \TEMP and \TMP on all drives taking the first
46 # wineconf doesn't support floppy drives, network drives, printers,
47 # and serial device configuration is hardcoded and not configured for
48 # the machine it runs on. Similarly, spy parameters are hard coded.
50 # It would make sense to incorporate much of the heuristic code in
51 # this program into a library to be shared with a dosemu configuration
52 # program, because it seems that at least some of the same stuff will
53 # be wanted. The program needs to be cleaned up still. A better tmp
54 # search algorithm could be written. A fast option is planned. Less
55 # Linux-dependence is desired. Should look for devices independent
56 # of /etc/fstab; then sanity checks on /etc/fstab can be performed.
64 print "Usage: $0 <options>\n";
65 # print "-fstab <filename> Location of alternate fstab file\n";
66 print "-windir <filename> Location of windows dir in DOS space\n";
67 print "-thorough Do careful analysis (default)\n";
68 print "-sysdir <filename> Location of systems dir in DOS space\n";
69 print "-inifile <filename> Path to the wine.ini file (by default './wine.ini')\n";
70 # print "-tmpdir <filename> Location of tmp directory\n";
71 print "Generates (to STDOUT) a wine configuration file based on\n";
72 print "/etc/fstab and searching around in DOS directories\n";
73 print "The options above can override certain values\n";
74 print "This should be considered ALPHA code\n";
78 # Returns 1 if the device is mounted; -1 if mount check failed; 0 if not
80 # This code is Linux specific, and needs to be broadened.
84 if (-e
"/proc/mounts") {
85 open(MOUNTS
, "/proc/mounts") ||
86 (warn "Cannot open /proc/mounts, although it exists\n" &&
90 return 1; # Tested 1.4
93 return 0; # Tested 1.4
99 sub RegisterDrive
($$) {
100 my($DOSdrive, $Drive) = @_;
101 $::DOS2Unix
{$DOSdrive} = $Drive;
102 $::Device2DOS
{$Drive->[0]} = $DOSdrive;
103 $::MntPoint2DOS
{$Drive->[1]} = $DOSdrive;
104 $::DOS2MntPoint
{$DOSdrive} = $Drive->[1];
105 $::DOS2Device
{$DOSdrive} = $Drive->[0];
109 my($DeviceA) = $a->[0];
110 my($DeviceB) = $b->[0];
112 # Primary drives come first, logical drives last
113 # DOS User's Guide (version 6) p. 70, IBM version.
114 # If both drives are the same type, sort alphabetically
115 # This makes drive a come before b, etc.
116 # It also makes SCSI drives come before IDE drives;
117 # this may or may not be right :-(
118 my($Alogical, $Blogical);
119 if (substr($DeviceA, 3, 1) >= 5) { $Alogical++; }
120 if (substr($DeviceB, 3, 1) >= 5) { $Blogical++; }
121 if ($Alogical && !$Blogical) { return -1; }
122 elsif ($Blogical && !$Alogical) { return 1; }
123 else { return ($DeviceA cmp $DeviceB); }
127 my($DeviceA) = $a->[0];
128 my($DeviceB) = $b->[0];
129 $DeviceA cmp $DeviceB;
133 $::opt_f
= $::opt_f ?
$::opt_f
: '/etc/fstab';
134 open(FSTAB
, $::opt_f
) || die "Cannot read $::opt_f\n";
139 my ($device, $mntpoint, $type, @rest) = split(' ', $_);
140 if ($device !~ m
"^/dev/fd") {
141 if ($type eq "ntfs") {
142 push(@
::FatDrives
, [$device, $mntpoint, 'win95']);
144 elsif ($type eq "msdos" || $type eq "vfat") {
145 push(@
::FatDrives
, [$device, $mntpoint, $type]);
147 elsif ($type eq "iso9660" ||
148 ($mntpoint eq "/cdrom" && ! $type eq 'supermount') ||
149 ($device eq '/dev/cdrom' && $type eq 'auto') ) {
150 push(@
::CdromDrives
, [$device, $mntpoint, 'win95']);
152 elsif ( ($mntpoint eq '/mnt/cdrom' || $mntpoint eq '/cdrom')
153 && $type eq 'supermount') {
154 push(@
::CdromDrives
, ['/dev/cdrom', $mntpoint, 'win95']);
159 warn "ERROR ($0): Cannot find any MSDOS drives.\n";
160 warn "This does not mean you cannot run Wine, but $0\n";
161 warn "cannot help you (yet)\n";
164 push(@
::UnixDrives
, ['', '/tmp', 'hd']);
165 push(@
::UnixDrives
, ['', '${HOME}', 'network']);
166 my $MagicDrive = 'C';
167 @
::FatDrives
= sort byDriveOrder @
::FatDrives
;
168 @
::CdromDrives
= sort byCdOrder @
::CdromDrives
;
169 foreach my $FatDrive (@
::FatDrives
) {
170 print "[Drive $MagicDrive]\n";
171 my $MntPoint = $FatDrive->[1];
172 my $FileSys = $FatDrive->[2];
173 print "\"Path\" = \"$MntPoint\"\n";
174 print "\"Type\" = \"hd\"\n";
175 print "\"Filesystem\" = \"$FileSys\"\n";
177 RegisterDrive
($MagicDrive, $FatDrive);
178 if(!IsMounted
($FatDrive->[0])) {
179 warn "WARNING: DOS Drive $MagicDrive (" . $FatDrive->[0] .
180 ") is not mounted\n";
184 foreach my $CdromDrive (@
::CdromDrives
) {
185 print "[Drive $MagicDrive]\n";
186 my $Device = $CdromDrive->[0];
187 my $MntPoint = $CdromDrive->[1];
188 my $FileSys = $CdromDrive->[2];
189 print "\"Path\" = \"$MntPoint\"\n";
190 print "\"Type\" = \"cdrom\"\n";
191 print "\"Device\" = \"$Device\"\n";
192 print "\"Filesystem\" = \"$FileSys\"\n";
194 RegisterDrive
($MagicDrive, $CdromDrive);
197 foreach my $UnixDrive (@
::UnixDrives
) {
198 print "[Drive $MagicDrive]\n";
199 my $MntPoint = $UnixDrive->[1];
200 my $Type = $UnixDrive->[2];
201 print "\"Path\" = \"$MntPoint\"\n";
202 print "\"Type\" = \"$Type\"\n";
203 print "\"Filesystem\" = \"win95\"\n";
209 # FNunix = ToUnix(FNdos);
210 # Converts DOS filenames to Unix filenames, leaving Unix filenames
216 # Initialize tables if necessary.
217 if (!%::DOS2Unix
) { ReadFSTAB
(); }
219 # Determine which type of conversion is necessary
220 if ($FNdos =~ /^([A-Z])\:(.*)$/) { # DOS drive specified
221 $FNunix = $::DOS2MntPoint
{$1} . "/$2";
223 elsif ($FNdos =~ m
%\\%) { # DOS drive not specified, C: is default
224 $FNunix = $::DOS2MntPoint
{"C"} . "/$FNdos";
226 else { # Unix filename
229 1 while ($FNunix =~ s
%\\%/%); # Convert \ to /
230 $FNunix =~ tr/A-Z/a-z/; # Translate to lower case
231 1 while ($FNunix =~ s
%//%/%); # Translate double / to
/
235 # FNdos = ToDos(FNunix)
236 # Converts Unix filenames to DOS filenames
239 my(@MntList) = keys %::MntPoint2DOS
;
240 my ($TheMntPt, $FNdos);
242 foreach my $MntPt (@MntList) { # Scan mount point list to see if path matches
243 if ($FNunix =~ /^$MntPt/) {
249 Carp
("ERROR: $FNunix not found in DOS directories\n");
253 $FNdos =~ s/^$TheMntPt//;
254 $FNdos = $::MntPoint2DOS
{$TheMntPt} . ":" . $FNdos;
255 1 while($FNdos =~ s
%/%\\%);
259 sub InsertDefaultFile
($$) {
260 my ($fileName, $tag) = @_;
263 if (open(DEFFILE
, "$fileName")) {
265 $state = 0 if ($state == 1 && $_ =~ /^[ \t]*\#/o && index($_, "[/$tag]") >= 0);
266 print $_ if ($state == 1);
267 $state = 1 if ($state == 0 && $_ =~ /^[ \t]*\#/o && index($_, "[$tag]" ) >= 0);
271 print STDERR
"Cannot read $fileName\n";
285 sub FindWindowsDir
() {
286 my($MagicDrive) = 'C';
287 my(@FATD)=@
::FatDrives
;
292 if (!$::opt_windir
&& !$::opt_fast
&& !$::opt_thorough
) {
296 $winini = ToUnix
($::opt_windir
);
298 die "ERROR: Specified winini file does not exist\n";
301 elsif ($::opt_fast
) {
302 die "-fast code can be implemented\n";
304 elsif ($::opt_thorough
) {
305 if ($::opt_debug
) { print STDERR
"DEBUG: Num FATD = ", $#FATD+1, "\n"; }
306 foreach $ThisDrive (@FATD) {
307 my $MntPoint = $ThisDrive->[1];
308 push(@wininis, `find $MntPoint -iname win.ini -print`);
310 foreach $winini (@wininis) {
313 my ($winini_cnt) = $#wininis+1;
315 print STDERR
"DEBUG: Num wininis found: $winini_cnt\n";}
316 if ($winini_cnt > 1) {
317 warn "$winini_cnt win.ini files found:\n";
318 @wininis = sort byFileAge
@wininis;
319 warn join("\n", @wininis), "\n";
320 $winini = $wininis[0];
321 warn "Using most recent one: $winini\n";
323 elsif ($winini_cnt == 0) {
324 die "ERROR: No win.ini found in DOS partitions\n";
327 $winini = $wininis[0];
331 die "ERROR: None of -windir, -fast, or -thorough set\n";
333 $::windir
= ToDos
(dirname
($winini));
335 print "\"windows\" = ", marshall
($::windir
), "\n";
337 print "\"system\" = ", marshall
($::opt_sysdir
), "\n";
340 print "\"system\" = ", marshall
("$::windir\\SYSTEM"), "\n";
344 sub ReadAutoexecBat
() {
345 if (!%::DOS2Unix
) { ReadFSTAB
(); }
346 my($DriveC) = $::DOS2MntPoint
{"C"};
350 print STDERR
"DEBUG: Looking for $DriveC/autoexec.bat\n"; }
351 if (-e
"$DriveC/autoexec.bat") {
353 open(AUTOEXEC
, "$DriveC/autoexec.bat") ||
354 die "Cannot read autoexec.bat\n";
357 if (/^\s*(set\s+)?(\w+)\s*[\s\=]\s*(.*)$/i) {
361 $varname =~ tr/A-Z/a-z/;
362 while ($varvalue =~ /%(\w+)%/) {
365 $subname =~ tr/A-Z/a-z/;
366 if (($::opt_debug
) && ($::opt_debug
=~ /path/i)) {
367 print STDERR
"DEBUG: Found $matchname as $subname\n";
368 print STDERR
"DEBUG: Old varvalue:\n$varvalue\n";
369 print STDERR
"DEBUG: Old subname value:\n" .
370 $::DOSenv
{$subname} . "\n";
372 if ($::DOSenv
{$subname}) {
373 $varvalue =~ s/\%$matchname\%/$::DOSenv{$subname}/;
376 warn "DOS environment variable $subname not\n";
377 warn "defined in autoexec.bat. (Reading config.sys\n";
378 warn "is not implemented.) Using null value\n";
379 $varvalue =~ s/%$matchname%//;
381 if (($::opt_debug
) && ($::opt_debug
=~ /path/i)) {
382 print STDERR
"DEBUG: New varvalue:\n$varvalue\n";
386 print STDERR
"DEBUG: $varname = $varvalue\n";
388 $::DOSenv
{$varname} = $varvalue;
395 warn "WARNING: C:\\AUTOEXEC.BAT was not found.\n";
398 if ($::DOSenv
{"path"}) {
399 my @pathdirs = split(/\s*;\s*/, $::DOSenv
{"path"});
400 if (($::opt_debug
) && ($::opt_debug
=~ /path/i)) {
401 print STDERR
"DEBUG (path): @pathdirs\n";
403 foreach my $pathdir (@pathdirs) {
404 if (-d ToUnix
($pathdir)) {
405 if ($::DOSpathdir
{$pathdir}++) {
406 warn "Ignoring duplicate DOS path entry $pathdir\n";
409 if (($::opt_debug
) && ($::opt_debug
=~ /path/i)) {
410 print STDERR
"DEBUG (path): Found $pathdir\n";
412 push(@
::DOSpathlist
, $pathdir);
416 warn "Ignoring DOS path directory $pathdir, as it does not\n";
420 print "\"path\" = ", marshall
(join (";", @
::DOSpathlist
)), "\n";
423 # Code status: tested 1.4
424 warn "WARNING: Making assumptions for PATH\n";
425 warn "Will scan windows directory for executables and generate\n";
426 warn "path from that\n";
427 my $shellcmd = 'find ' . ToUnix
($::windir
) . " -iregex '" .
428 '.*\.\(exe\|bat\|com\|dll\)' . "' -print";
430 print STDERR
"DEBUG: autoexec.bat search command:\n $shellcmd\n";
432 push(@
::DOScommand
, `$shellcmd`);
433 if ($::opt_debug
&& $::opt_debug
=~ /autoexec/i) {
434 print STDERR
"DEBUG: autoexec.bat search results:\n\@DOS::command\n";
436 foreach my $command (@
::DOScommand
) {
437 $command =~ s
%[^/]+$%%;
438 $::DOSexecdir
{ToDos
($command)}++;
440 print "\"path\" = " .
443 sort {$::DOSexecdir
{$b} <=> $::DOSexecdir
{$a}}
444 (keys %::DOSexecdir
)))) . "\n";
447 if ($::DOSenv
{"temp"} && -d ToUnix
($::DOSenv
{"temp"})) {
448 print "\"temp\" = ", marshall
($::DOSenv
{"temp"}), "\n";
453 warn "WARNING: Making assumptions for TEMP\n";
454 warn "Looking for \\TEMP and then \\TMP on every drive\n";
455 # Watch out .. might pick CDROM drive :-)
456 foreach my $DOSdrive (keys %::DOS2Unix
) {
457 my $tmp = ToUnix
("$DOSdrive:\\temp");
458 if (-d
$tmp) { $TheTemp = "$DOSdrive:\\temp"; last; }
459 $tmp = ToUnix
("$DOSdrive:\\tmp");
460 if (-d
$tmp) { $TheTemp = "$DOSdrive:\\tmp"; last; }
462 $TheTemp = '/tmp' if (!$TheTemp && -d
'/tmp');
464 warn "Using $TheTemp\n";
465 print "\"temp\" = ", marshall
($TheTemp), "\n";
469 print "\"temp\" = ", marshall
("C:\\"), "\n";
475 sub StandardStuff
() {
476 if (!$::opt_inifile
) {
477 InsertDefaultFile
("./wine.ini", "wineconf");
479 InsertDefaultFile
($::opt_inifile
, "wineconf");
485 GetOptions
('windir=s', 'sysdir=s', 'thorough', 'debug:s', 'inifile=s') || Usage
;
487 print "WINE REGISTRY Version 2\n";
488 print ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n";