1 #!/usr/local/bin/perl -w
3 # Detect the operating system and version.
7 # Package scoped for mapping short names to long "proper" names
12 if ($#ARGV < 1) { die "Usage: $0 os_list.txt outfile [0|1|2|3] [issue]\n"; }
13 my ($oslist, $out, $auto, $issue) = @ARGV;
14 return write_file($out, oschooser($oslist, $auto, $issue));
16 main() unless caller(); # make it testable and usable as a library
21 my ($oslist, $auto, $issue) = @_;
24 my ($list_ref, $names_ref) = parse_patterns($oslist);
26 if ($auto && ($ver_ref = auto_detect($oslist, $issue, $list_ref, $names_ref))) {
27 return ($ver_ref->[2], $ver_ref->[3], $ver_ref->[0], $ver_ref->[1]);
29 elsif (!$auto || ($auto == 3 && have_tty()) || $auto == 2) {
30 $ver_ref = ask_user($names_ref, $list_ref);
31 return ($ver_ref->[2], $ver_ref->[3], $ver_ref->[0], $ver_ref->[1]);
34 print "Failed to detect operating system\n";
39 # Return a reference to a pre-parsed list array, and a ref to a names array
45 # Parse the patterns file
46 open(OS, "<$oslist") || die "failed to open $oslist : $!";
49 if (/^([^\t]+)\t+([^\t]+)\t+([^\t]+)\t+([^\t]+)\t*(.*)$/) {
50 push(@list, [ $1, $2, $3, $4, $5 ]);
51 push(@names, $1) if (!$donename{$1}++);
52 $NAMES_TO_REAL{$1} ||= $3;
56 return (\@list, \@names);
59 # auto_detect($oslist, $issue)
60 # Returns detected OS details in a hash ref
62 my ($oslist, $issue, $list_ref) = @_;
64 my @list = @$list_ref;
66 # Try to guess the OS name and version
68 my $uname = `uname -a`;
71 $etc_issue = `cat $issue`;
72 $uname = $etc_issue; # Strangely, I think this will work fine.
74 elsif (-r "/etc/.issue") {
75 $etc_issue = `cat /etc/.issue`;
77 elsif (-r "/etc/issue") {
78 $etc_issue = `cat /etc/issue`;
81 foreach my $o_ref (@list) {
82 if ($issue && $o_ref->[4]) {
83 $o_ref->[4] =~ s#cat [/a-zA-Z\-\s]*\s2#cat $issue 2#g;
84 } # Testable, but this regex substitution is dumb.XXX
85 local $^W = 0; # Disable warnings for evals, which may have undefined vars
86 if ($o_ref->[4] && eval "$o_ref->[4]") {
87 # Got a match! Resolve the versions
88 print "$o_ref->[4]\n";
90 if ($ver_ref->[1] =~ /\$/) {
91 $ver_ref->[1] = eval "($o_ref->[4]); $ver_ref->[1]";
93 if ($ver_ref->[3] =~ /\$/) {
94 $ver_ref->[3] = eval "($o_ref->[4]); $ver_ref->[3]";
99 print STDERR "Error parsing $o_ref->[4]\n";
106 my ($names_ref, $list_ref) = @_;
107 my @names = @$names_ref;
108 my @list = @$list_ref;
111 # ask for the operating system name ourselves
112 my $dashes = "-" x 75;
114 For Webmin to work properly, it needs to know which operating system
115 type and version you are running. Please select your system type by
116 entering the number next to it from the list below
121 for($i=0; $i<@names; $i++) {
122 printf " %2d) %-20.20s ", $i+1, $names[$i];
123 print "\n" if ($i%3 == 2);
125 print "\n" if ($i%3);
128 print "Operating system: ";
129 chop($osnum = <STDIN>);
130 if ($osnum !~ /^\d+$/) {
131 print "ERROR: You must enter the number next to your operating\n";
132 print "system, not its name or version number.\n\n";
135 if ($osnum < 1 || $osnum > @names) {
136 print "ERROR: $osnum is not a valid operating system number.\n\n";
141 # Ask for the operating system version
142 my $name = $names[$osnum-1];
144 Please enter the version of $name you are running
147 chop($vnum = <STDIN>);
148 if ($vnum !~ /^\S+$/) {
149 print "ERROR: An operating system number cannot contain\n\n";
150 print "spaces. It must be like 2.1 or ES4.0.\n";
154 return [ $name, $vnum,
155 $NAMES_TO_REAL{$name}, $vnum ];
158 # write_file($out, $os_type, $os_version, $real_os_type, $real_os_version)
159 # Write the name, version and real name and version to a file
161 my ($out, $os_type, $os_version, $real_os_type, $real_os_version) = @_;
162 open(OUT, ">$out") or die "Failed to open $out for writing.";
163 print OUT "os_type='",$os_type,"'\n";
164 print OUT "os_version='",$os_version,"'\n";
165 print OUT "real_os_type='",$real_os_type,"'\n";
166 print OUT "real_os_version='",$real_os_version,"'\n";
173 my $rv = system("tty >/dev/null 2>&1");
188 Attempt to detect operating system and version, or ask the user to select
189 from a list. Works from the command line, for usage from shell scripts,
190 or as a library for use within Perl scripts.
192 =head2 COMMAND LINE USE
194 OsChooser.pm os_list.txt outfile [auto] [issue]
196 Where "auto" can be the following values:
206 automatic, give up if fails
210 automatic, ask user if fails
214 automatic, ask user if fails and if a TTY
221 my ($os_type, $version, $real_os_type, $real_os_version) =
222 OsChooser->oschooser("os_list.txt", "outfile", $auto, [$issue]);