From 8c79fcdd11d0de35239319b8bf650d180402c221 Mon Sep 17 00:00:00 2001 From: Joe Cooper Date: Mon, 11 Aug 2008 23:28:08 +0000 Subject: [PATCH] Make Slackware detection more specific, add OsChooser.pm --- OsChooser.pm | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++ os_list.txt | 2 +- 2 files changed, 226 insertions(+), 1 deletion(-) create mode 100755 OsChooser.pm diff --git a/OsChooser.pm b/OsChooser.pm new file mode 100755 index 000000000..a90f5f280 --- /dev/null +++ b/OsChooser.pm @@ -0,0 +1,225 @@ +#!/usr/local/bin/perl -w +use strict; +# Detect the operating system and version. + +package OsChooser; + +# Package scoped for mapping short names to long "proper" names +my %NAMES_TO_REAL; + +# main +sub main { + if ($#ARGV < 1) { die "Usage: $0 os_list.txt outfile [0|1|2|3] [issue]\n"; } + my ($oslist, $out, $auto, $issue) = @ARGV; + return write_file($out, oschooser($oslist, $auto, $issue)); + } +main() unless caller(); # make it testable and usable as a library + +$| = 1; + +sub oschooser { +my ($oslist, $auto, $issue) = @_; +my $ver_ref; + +my ($list_ref, $names_ref) = parse_patterns($oslist); + +if ($auto && ($ver_ref = auto_detect($oslist, $issue, $list_ref, $names_ref))) { + return ($ver_ref->[2], $ver_ref->[3], $ver_ref->[0], $ver_ref->[1]); + } +elsif (!$auto || ($auto == 3 && have_tty()) || $auto == 2) { + $ver_ref = ask_user($names_ref, $list_ref); + return ($ver_ref->[2], $ver_ref->[3], $ver_ref->[0], $ver_ref->[1]); + } +else { + print "Failed to detect operating system\n"; + exit 1; + } +} + +# Return a reference to a pre-parsed list array, and a ref to a names array +sub parse_patterns { +my ($oslist) = @_; +my @list; +my @names; +my %donename; +# Parse the patterns file +open(OS, "<$oslist") || die "failed to open $oslist : $!"; +while() { + chop; + if (/^([^\t]+)\t+([^\t]+)\t+([^\t]+)\t+([^\t]+)\t*(.*)$/) { + push(@list, [ $1, $2, $3, $4, $5 ]); + push(@names, $1) if (!$donename{$1}++); + $NAMES_TO_REAL{$1} ||= $3; + } + } +close(OS); +return (\@list, \@names); +} + +# auto_detect($oslist, $issue) +# Returns detected OS details in a hash ref +sub auto_detect { +my ($oslist, $issue, $list_ref) = @_; +my $ver_ref; +my @list = @$list_ref; + +# Try to guess the OS name and version +my $etc_issue; +my $uname = `uname -a`; + +if ($issue) { + $etc_issue = `cat $issue`; + $uname = $etc_issue; # Strangely, I think this will work fine. + } +elsif (-r "/etc/.issue") { + $etc_issue = `cat /etc/.issue`; + } +elsif (-r "/etc/issue") { + $etc_issue = `cat /etc/issue`; + } + +foreach my $o_ref (@list) { + if ($issue && $o_ref->[4]) { + $o_ref->[4] =~ s#cat [/a-zA-Z\-\s]*\s2#cat $issue 2#g; + } # Testable, but this regex substitution is dumb.XXX + local $^W = 0; # Disable warnings for evals, which may have undefined vars + if ($o_ref->[4] && eval "$o_ref->[4]") { + # Got a match! Resolve the versions + print "$o_ref->[4]\n"; + $ver_ref = $o_ref; + if ($ver_ref->[1] =~ /\$/) { + $ver_ref->[1] = eval "($o_ref->[4]); $ver_ref->[1]"; + } + if ($ver_ref->[3] =~ /\$/) { + $ver_ref->[3] = eval "($o_ref->[4]); $ver_ref->[3]"; + } + last; + } + if ($@) { + print STDERR "Error parsing $o_ref->[4]\n"; + } + } + return $ver_ref; +} + +sub ask_user { +my ($names_ref, $list_ref) = @_; +my @names = @$names_ref; +my @list = @$list_ref; +my $vnum; +my $osnum; +# ask for the operating system name ourselves +my $dashes = "-" x 75; +print <); +if ($osnum !~ /^\d+$/) { + print "ERROR: You must enter the number next to your operating\n"; + print "system, not its name or version number.\n\n"; + exit 9; + } +if ($osnum < 1 || $osnum > @names) { + print "ERROR: $osnum is not a valid operating system number.\n\n"; + exit 10; + } +print "\n"; + +# Ask for the operating system version +my $name = $names[$osnum-1]; +print <); +if ($vnum !~ /^\S+$/) { + print "ERROR: An operating system number cannot contain\n\n"; + print "spaces. It must be like 2.1 or ES4.0.\n"; + exit 10; + } +print "\n"; +return [ $name, $vnum, + $NAMES_TO_REAL{$name}, $vnum ]; +} + +# write_file($out, $os_type, $os_version, $real_os_type, $real_os_version) +# Write the name, version and real name and version to a file +sub write_file { +my ($out, $os_type, $os_version, $real_os_type, $real_os_version) = @_; +open(OUT, ">$out") or die "Failed to open $out for writing."; +print OUT "os_type='",$os_type,"'\n"; +print OUT "os_version='",$os_version,"'\n"; +print OUT "real_os_type='",$real_os_type,"'\n"; +print OUT "real_os_version='",$real_os_version,"'\n"; +return close(OUT); +} + +sub have_tty +{ +# Do we have a tty? +my $rv = system("tty >/dev/null 2>&1"); +if ($?) { + return 0; + } +else { + return 1; + } +} + +1; + +__END__ + +=head1 OsChooser.pm + +Attempt to detect operating system and version, or ask the user to select +from a list. Works from the command line, for usage from shell scripts, +or as a library for use within Perl scripts. + +=head2 COMMAND LINE USE + +OsChooser.pm os_list.txt outfile [auto] [issue] + +Where "auto" can be the following values: + +=over 4 + +=item 0 + +always ask user + +=item 1 + +automatic, give up if fails + +=item 2 + +automatic, ask user if fails + +=item 3 + +automatic, ask user if fails and if a TTY + +=back + +=head2 SYNOPSIS + + use OsChooser; + my ($os_type, $version, $real_os_type, $real_os_version) = + OsChooser->oschooser("os_list.txt", "outfile", $auto, [$issue]); + +=cut + diff --git a/os_list.txt b/os_list.txt index 8d10abcc2..6164f1bd8 100644 --- a/os_list.txt +++ b/os_list.txt @@ -52,7 +52,7 @@ White Dwarf Linux 2.1.0 slackware-linux 8.1 `cat /tmp/wd/version 2>/dev/null` = Slamd64 Linux $1 slackware-linux 11.1 `cat /etc/slamd64-version 2>/dev/null` =~ /\s([0-9\.]+)/ # Slackware Linux -Slackware Linux $1 slackware-linux $1 `cat /etc/slackware-version 2>/dev/null` =~ /([0-9\.]+)/ +Slackware Linux $1 slackware-linux $1 `cat /etc/slackware-version 2>/dev/null` =~ /Slackware ([0-9\.]+)/i # Debian clones Xandros Linux 2.0 debian-linux 3.0 $etc_issue =~ /Xandros.*\s2\.0/i