3 # This program generates wine.conf files on STDOUT.
4 # (C) 1996 Stephen Simmons
5 # Redistributable under Wine License
9 # This program examines the contents of the DOS filesystems and
10 # attempts to generate a sensible wine.conf file. This is output
12 # It reads /etc/FSTAB to find mounting locations of the hard disk drives
13 # It uses the correct algorithm for ordering DOS drives, with the
14 # exception of the case of multiple drive controller types, where I don't
15 # know what DOS's algorithm is.
16 # It uses find to find all of the win.ini files on any DOS partition
17 # and sorts them by age to guess which is part of the active Windows
19 # It reads the autoexec.bat file (if found) and records all variable
20 # settings. There are some inaccuracies in its determination.
21 # First, while variables are interpolated properly, no control
22 # structures are supported so calls and execs to other batch files are
23 # ignored, and all variable settings take effect regardless of whether
24 # they would in DOS (i,e., both if and else clauses are read).
25 # This is used to determine the path and temp directories. Duplicate
26 # path directories and path directories that don't exist are thrown
28 # On failing to find C:\AUTOEXEC.BAT, wineconf finds all executables
29 # in the windows directory and subdirectories, and generates an
30 # optimized path statement encompassing all the executables.
31 # Then it also looks for \TEMP and \TMP on all drives taking the first
33 # wineconf doesn't support floppy drives, network drives, printers,
34 # and serial device configuration is hardcoded and not configured for
35 # the machine it runs on. Similarly, spy parameters are hard coded.
37 # It would make sense to incorporate much of the hueristic code in
38 # this program into a library to be shared with a dosemu configuration
39 # program, because it seems that at least some of the same stuff will
40 # be wanted. The program needs to be cleaned up still. A better tmp
41 # search algorithm could be written. A fast option is planned. Less
42 # Linux-dependence is desired. Should look for devices independent
43 # of /etc/fstab; then sanity checks on /etc/fstab can be performed.
50 GetOptions
('windir=s', 'sysdir=s', 'thorough', 'debug:s') || &Usage
;
58 print "Usage: $0 <options>\n";
59 # print "-fstab <filename> Location of alternate fstab file\n";
60 print "-windir <filename> Location of windows dir in DOS space\n";
61 print "-thorough Do careful analysis (default)\n";
62 print "-sysdir <filename> Location of systems dir in DOS space\n";
63 # print "-tmpdir <filename> Location of tmp directory\n";
64 print "Generates (to STDOUT) a wine configuration file based on\n";
65 print "/etc/fstab and searching around in DOS directories\n";
66 print "The options above can override certain values\n";
67 print "This should be considered ALPHA code\n";
72 $::opt_f
= $::opt_f ?
$::opt_f
: '/etc/fstab';
73 open(FSTAB
, $::opt_f
) || die "Cannot read $::opt_f\n";
78 my ($device, $mntpoint, $type, @rest) = split(' ', $_);
79 if ($device !~ m
"^/dev/fd") {
80 if ($type eq "msdos" || $type eq "vfat") {
81 push(@
::FatDrives
, [$device, $mntpoint, $type]);
83 elsif ($type eq "iso9660" ||
84 $mntpoint eq "/cdrom" ||
85 ($device eq '/dev/cdrom' && $type eq 'auto') ) {
86 push(@
::CdromDrives
, [$device, $mntpoint, 'win95']);
91 warn "ERROR ($0): Cannot find any MSDOS drives.\n";
92 warn "This does not mean you cannot run Wine, but $0\n";
93 warn "cannot help you (yet)\n";
96 push(@
::UnixDrives
, ['', '/tmp', 'hd']);
97 push(@
::UnixDrives
, ['', '${HOME}', 'network']);
99 @
::FatDrives
= sort byDriveOrder @
::FatDrives
;
100 @
::CdromDrives
= sort byCdOrder @
::CdromDrives
;
101 foreach my $FatDrive (@
::FatDrives
) {
102 print "[Drive $MagicDrive]\n";
103 my $MntPoint = $FatDrive->[1];
104 my $FileSys = $FatDrive->[2];
105 print "Path=$MntPoint\n";
107 print "Filesystem=$FileSys\n";
109 &RegisterDrive
($MagicDrive, $FatDrive);
110 if(!&IsMounted
($FatDrive->[0])) {
111 warn "WARNING: DOS Drive $MagicDrive (" . $FatDrive->[0] .
112 ") is not mounted\n";
116 foreach my $CdromDrive (@
::CdromDrives
) {
117 print "[Drive $MagicDrive]\n";
118 my $Device = $CdromDrive->[0];
119 my $MntPoint = $CdromDrive->[1];
120 my $FileSys = $CdromDrive->[2];
121 print "Path=$MntPoint\n";
122 print "Type=cdrom\n";
123 print "Device=$Device\n";
124 print "Filesystem=$FileSys\n";
126 &RegisterDrive
($MagicDrive, $CdromDrive);
129 foreach my $UnixDrive (@
::UnixDrives
) {
130 print "[Drive $MagicDrive]\n";
131 my $MntPoint = $UnixDrive->[1];
132 my $Type = $UnixDrive->[2];
133 print "Path=$MntPoint\n";
134 print "Type=$Type\n";
135 print "Filesystem=win95\n";
142 my($MagicDrive) = 'C';
143 my(@FATD)=@
::FatDrives
;
147 if (!$::opt_windir
&& !$::opt_fast
&& !$::opt_thorough
) {
151 $winini = &ToUnix
($::opt_windir
);
153 die "ERROR: Specified winini file does not exist\n";
156 elsif ($::opt_fast
) {
157 die "-fast code can be implemented\n";
159 elsif ($::opt_thorough
) {
160 if ($::opt_debug
) { print STDERR
"DEBUG: Num FATD = ", $#FATD+1, "\n"; }
162 my $ThisDrive = shift(@FATD);
163 my $MntPoint = $ThisDrive->[1];
164 push(@wininis, `find $MntPoint -name win.ini -print`);
166 foreach $winini (@wininis) {
169 my ($winini_cnt) = $#wininis+1;
171 print STDERR
"DEBUG: Num wininis found: $winini_cnt\n";}
172 if ($winini_cnt > 1) {
173 warn "$winini_cnt win.ini files found:\n";
174 @wininis = sort byFileAge
@wininis;
175 warn join("\n", @wininis), "\n";
176 $winini = $wininis[0];
177 warn "Using most recent one: $winini\n";
179 elsif ($winini_cnt == 0) {
180 die "ERROR: No win.ini found in DOS partitions\n";
183 $winini = $wininis[0];
187 die "ERROR: None of -windir, -fast, or -thorough set\n";
189 $::windir
= &ToDos
(dirname
($winini));
191 print "windows=$::windir\n";
193 print "system=$::opt_sysdir\n";
196 print "system=$::windir\\SYSTEM\n";
200 # Returns 1 if the device is mounted; -1 if mount check failed; 0 if not
202 # This code is Linux specific, and needs to be broadened.
206 if (-e
"/proc/mounts") {
207 open(MOUNTS
, "/proc/mounts") ||
208 (warn "Cannot open /proc/mounts, although it exists\n" &&
212 return 1; # Tested 1.4
215 return 0; # Tested 1.4
222 my($DOSdrive, $Drive, $Type) = @_;
223 $::DOS2Unix
{$DOSdrive} = $Drive;
224 $::Device2DOS
{$Drive->[0]} = $DOSdrive;
225 $::MntPoint2DOS
{$Drive->[1]} = $DOSdrive;
226 $::DOS2MntPoint
{$DOSdrive} = $Drive->[1];
227 $::DOS2Device
{$DOSdrive} = $Drive->[0];
230 sub ReadAutoexecBat
{
231 if (!%::DOS2Unix
) { &ReadFSTAB
; }
232 my($DriveC) = $::DOS2MntPoint
{"C"};
236 print STDERR
"DEBUG: Looking for $DriveC/autoexec.bat\n"; }
237 if (-e
"$DriveC/autoexec.bat") {
239 open(AUTOEXEC
, "$DriveC/autoexec.bat") ||
240 die "Cannot read autoexec.bat\n";
243 if (/^\s*(set\s+)?(\w+)\s*[\s\=]\s*(.*)$/i) {
247 $varname =~ tr/A-Z/a-z/;
248 while ($varvalue =~ /%(\w+)%/) {
251 $subname =~ tr/A-Z/a-z/;
252 if ($::opt_debug
=~ /path/i) {
253 print STDERR
"DEBUG: Found $matchname as $subname\n";
254 print STDERR
"DEBUG: Old varvalue:\n$varvalue\n";
255 print STDERR
"DEBUG: Old subname value:\n" .
256 $::DOSenv
{$subname} . "\n";
258 if ($::DOSenv
{$subname}) {
259 $varvalue =~ s/\%$matchname\%/$::DOSenv{$subname}/;
262 warn "DOS environment variable $subname not\n";
263 warn "defined in autoexec.bat. (Reading config.sys\n";
264 warn "is not implemented.) Using null value\n";
265 $varvalue =~ s/%$matchname%//;
267 if ($::opt_debug
=~ /path/i) {
268 print STDERR
"DEBUG: New varvalue:\n$varvalue\n";
272 print STDERR
"DEBUG: $varname = $varvalue\n";
274 $::DOSenv
{$varname} = $varvalue;
281 warn "WARNING: C:\\AUTOEXEC.BAT was not found.\n";
284 if ($::DOSenv
{"path"}) {
285 my @pathdirs = split(/\s*;\s*/, $::DOSenv
{"path"});
286 if ($::opt_debug
=~ /path/i) {
287 print STDERR
"DEBUG (path): @pathdirs\n";
289 foreach my $pathdir (@pathdirs) {
290 if (-d
&ToUnix
($pathdir)) {
291 if ($::DOSpathdir
{$pathdir}++) {
292 warn "Ignoring duplicate DOS path entry $pathdir\n";
295 if ($::opt_debug
=~ /path/i) {
296 print STDERR
"DEBUG (path): Found $pathdir\n";
298 push(@
::DOSpathlist
, $pathdir);
302 warn "Ignoring DOS path directory $pathdir, as it does not\n";
306 print "path=" . join(";", @
::DOSpathlist
) . "\n";
309 # Code status: tested 1.4
310 warn "WARNING: Making assumptions for PATH\n";
311 warn "Will scan windows directory for executables and generate\n";
312 warn "path from that\n";
313 my $shellcmd = 'find ' . &ToUnix
($::windir
) . " -iregex '" .
314 '.*\.\(exe\|bat\|com\|dll\)' . "' -print";
316 print STDERR
"DEBUG: autoexec.bat search command:\n $shellcmd\n";
318 push(@
::DOScommand
, `$shellcmd`);
319 if ($::opt_debug
&& $::opt_debug
=~ /autoexec/i) {
320 print STDERR
"DEBUG: autoexec.bat search results:\n\@DOS::command\n";
322 foreach my $command (@
::DOScommand
) {
323 $command =~ s
%[^/]+$%%;
324 $::DOSexecdir
{$command}++;
329 sort {$::DOSexecdir
{$b} <=> $::DOSexecdir
{$a}}
330 (keys %::DOSexecdir
))) . "\n";
333 if ($::DOSenv
{"temp"} && -d
&ToUnix
($::DOSenv
{"temp"})) {
334 print "temp=" . $::DOSenv
{"temp"} . "\n";
339 warn "WARNING: Making assumptions for TEMP\n";
340 warn "Looking for \\TEMP and then \\TMP on every drive\n";
341 # Watch out .. might pick CDROM drive :-)
342 foreach my $DOSdrive (keys %::DOS2Unix
) {
343 my $tmp = &ToUnix
("$DOSdrive:\\temp");
344 if (-d
$tmp) { $TheTemp = "$DOSdrive:\\temp"; last; }
345 $tmp = &ToUnix
("$DOSdrive:\\tmp");
346 if (-d
$tmp) { $TheTemp = "$DOSdrive:\\tmp"; last; }
348 $TheTemp = '/tmp' if (!$TheTemp && -d
'/tmp');
350 warn "Using $TheTemp\n";
351 print "temp=$TheTemp\n";
361 # FNunix = &ToUnix(FNdos);
362 # Converts DOS filenames to Unix filenames, leaving Unix filenames
368 # Initialize tables if necessary.
369 if (!%::DOS2Unix
) { &ReadFSTAB
; }
371 # Determine which type of conversion is necessary
372 if ($FNdos =~ /^([A-Z])\:(.*)$/) { # DOS drive specified
373 $FNunix = $::DOS2MntPoint
{$1} . "/$2";
375 elsif ($FNdos =~ m
%\\%) { # DOS drive not specified, C: is default
376 $FNunix = $::DOS2MntPoint
{"C"} . "/$FNdos";
378 else { # Unix filename
381 1 while ($FNunix =~ s
%\\%/%); # Convert \ to /
382 $FNunix =~ tr/A-Z/a-z/; # Translate to lower case
383 1 while ($FNunix =~ s
%//%/%); # Translate double / to
/
387 # FNdos = &ToDOS(FNunix)
388 # Converts Unix filenames to DOS filenames
391 my(@MntList) = keys %::MntPoint2DOS
;
392 my ($TheMntPt, $FNdos);
394 foreach my $MntPt (@MntList) { # Scan mount point list to see if path matches
395 if ($FNunix =~ /^$MntPt/) {
401 Carp
("ERROR: $FNunix not found in DOS directories\n");
405 $FNdos =~ s/^$TheMntPt//;
406 $FNdos = $::MntPoint2DOS
{$TheMntPt} . ":" . $FNdos;
407 1 while($FNdos =~ s
%/%\\%);
411 sub InsertDefaultFile
{
412 my ($fileName, $tag) = @_;
415 if (open(DEFFILE
, "$fileName")) {
417 $state = 0 if ($state == 1 && $_ =~ /^[ \t]*\#/o && index($_, "</$tag>") >= 0);
418 print $_ if ($state == 1);
419 $state = 1 if ($state == 0 && $_ =~ /^[ \t]*\#/o && index($_, "<$tag>" ) >= 0);
423 print STDERR
"Cannot read $fileName\n";
428 &InsertDefaultFile
("./wine.ini", "wineconf");
436 my($DeviceA) = $a->[0];
437 my($DeviceB) = $b->[0];
439 # Primary drives come first, logical drives last
440 # DOS User's Guide (version 6) p. 70, IBM version.
441 # If both drives are the same type, sort alphabetically
442 # This makes drive a come before b, etc.
443 # It also makes SCSI drives come before IDE drives;
444 # this may or may not be right :-(
445 my($Alogical, $Blogical);
446 if (substr($DeviceA, 3, 1) >= 5) { $Alogical++; }
447 if (substr($DeviceB, 3, 1) >= 5) { $Blogical++; }
448 if ($Alogical && !$Blogical) { return -1; }
449 elsif ($Blogical && !$Alogical) { return 1; }
450 else { return ($DeviceA cmp $DeviceB); }
454 my($DeviceA) = $a->[0];
455 my($DeviceB) = $b->[0];
456 $DeviceA cmp $DeviceB;