package install::any; # $Id$

use strict;

our @ISA = qw(Exporter);
our @EXPORT_OK = qw(addToBeDone);

#-######################################################################################
#- misc imports
#-######################################################################################
use common;
use run_program;
use fs::type;
use fs::format;
use fs::any;
use partition_table;
use devices;
use modules;
use detect_devices;
use install::media 'getFile_';
use lang;
use any;
use log;

our @advertising_images;

sub drakx_version { 
    my ($o) = @_;

    if ($::move) {
	sprintf "DrakX-move v%s", cat_('/usr/bin/stage2/move.pm') =~ /move\.pm,v (\S+ \S+ \S+)/;
    } else {
	my $version = cat__(getFile_($o->{stage2_phys_medium}, "install/stage2/VERSION"));
	sprintf "DrakX v%s", chomp_($version);
    }
}

#-######################################################################################
#- Functions
#-######################################################################################
sub dont_run_directly_stage2() {
    readlink("/usr/bin/runinstall2") eq "runinstall2.sh";
}

sub is_network_install {
    my ($o) = @_;
    member($o->{method}, qw(ftp http nfs));
}


sub start_i810fb() {
    my ($vga) = cat_('/proc/cmdline') =~ /vga=(\S+)/;
    return if !$vga || listlength(cat_('/proc/fb'));

    my %vga_to_xres = (0x311 => '640', 0x314 => '800', 0x317 => '1024');
    my $xres = $vga_to_xres{$vga} || '800';

    log::l("trying to load i810fb module with xres <$xres> (vga was <$vga>)");
    eval { modules::load('intel_agp') };
    eval {
	my $opt = "xres=$xres hsync1=32 hsync2=48 vsync1=50 vsync2=70 vram=2 bpp=16 accel=1 mtrr=1"; #- this sucking i810fb does not accept floating point numbers in hsync!
	modules::load_with_options([ 'i810fb' ], { i810fb => $opt }); 
    };
}

sub spawnShell() {
    return if $::local_install || $::testing || dont_run_directly_stage2();

    my $shellpid_file = '/var/run/drakx_shell.pid';
    return if -e $shellpid_file && -d '/proc/' . chomp_(cat_($shellpid_file));

    if (my $shellpid = fork()) {
        output($shellpid_file, $shellpid);
        return;
    }

    $ENV{DISPLAY} ||= ":0"; #- why not :pp

    local *F;
    sysopen F, "/dev/tty2", 2 or log::l("cannot open /dev/tty2 -- no shell will be provided: $!"), goto cant_spawn;

    open STDIN, "<&F" or goto cant_spawn;
    open STDOUT, ">&F" or goto cant_spawn;
    open STDERR, ">&F" or goto cant_spawn;
    close F;

    print drakx_version($::o), "\n";

    c::setsid();

    ioctl(STDIN, c::TIOCSCTTY(), 0) or warn "could not set new controlling tty: $!";

    my @args; -e '/etc/bashrc' and @args = qw(--rcfile /etc/bashrc);
    foreach (qw(/bin/bash /usr/bin/busybox /bin/sh)) {
        -x $_ or next;
        my $program_name = /busybox/ ? "/bin/sh" : $_;  #- since perl_checker is too dumb
        exec { $_ } $program_name, @args or log::l("exec of $_ failed: $!");
    }

    log::l("cannot open any shell");
cant_spawn:
    c::_exit(1);
}

sub getAvailableSpace {
    my ($o) = @_;

    #- make sure of this place to be available for installation, this could help a lot.
    #- currently doing a very small install use 36Mb of postinstall-rpm, but installing
    #- these packages may eat up to 90Mb (of course not all the server may be installed!).
    #- 65mb may be a good choice to avoid almost all problem of insuficient space left...
    my $minAvailableSize = 65 * sqr(1024);

    my $n = !$::testing && getAvailableSpace_mounted($::prefix) || 
            getAvailableSpace_raw($o->{fstab}) * 512 / 1.07;
    $n - max(0.1 * $n, $minAvailableSize);
}

sub getAvailableSpace_mounted {
    my ($prefix) = @_;
    my $dir = -d "$prefix/usr" ? "$prefix/usr" : $prefix;
    my (undef, $free) = MDK::Common::System::df($dir) or return;
    log::l("getAvailableSpace_mounted $free KB");
    $free * 1024 || 1;
}
sub getAvailableSpace_raw {
    my ($fstab) = @_;

    do { $_->{mntpoint} eq '/usr' and return $_->{size} } foreach @$fstab;
    do { $_->{mntpoint} eq '/'    and return $_->{size} } foreach @$fstab;

    if ($::testing) {
	my $nb = 450;
	log::l("taking ${nb}MB for testing");
	return MB($nb);
    }
    die "missing root partition";
}

sub preConfigureTimezone {
    my ($o) = @_;
    require timezone;
   
    #- can not be done in install cuz' timeconfig %post creates funny things
    add2hash($o->{timezone}, timezone::read()) if $o->{isUpgrade};

    $o->{timezone}{timezone} ||= timezone::bestTimezone($o->{locale}{country});

    my $utc = every { !isFat_or_NTFS($_) } @{$o->{fstab}};
    my $ntp = timezone::ntp_server();
    add2hash_($o->{timezone}, { UTC => $utc, ntp => $ntp });
}

sub ask_suppl_media_method {
    my ($o) = @_;
    our $suppl_already_asked;

    my $msg = $suppl_already_asked
      ? N("Do you have further supplementary media?")
      : formatAlaTeX(
#-PO: keep the double empty lines between sections, this is formatted a la LaTeX
	    N("The following media have been found and will be used during install: %s.


Do you have a supplementary installation medium to configure?",
	    join(", ", map { $_->{name} } install::media::allMediums($o->{packages}))));

    my %l = my @l = (
	''      => N("None"),
	'cdrom' => N("CD-ROM"),
	'http'  => N("Network (HTTP)"),
	'ftp'   => N("Network (FTP)"),
	'nfs'   => N("Network (NFS)"),
    );

    $o->ask_from(
	'', $msg,
	[ {
	    val => \my $suppl,
	    list => [ map { $_->[0] } group_by2(@l) ],
	    type => 'list',
	    format => sub { $l{$_[0]} },
	} ],
    );

    $suppl_already_asked = 1;
    $suppl;
}

#- if the supplementary media is networked, but not the main one, network
#- support must be installed and network started.
sub prep_net_suppl_media {
    my ($o) = @_;

    require network::tools;
    my (undef, $is_up, undef) = network::tools::get_internet_connection($o->{net});

    return if our $net_suppl_media_configured && $is_up;
    $net_suppl_media_configured = 1;

    #- install basesystem now
    $o->do_pkgs->ensure_is_installed('basesystem', undef, 1);

    require network::netconnect;
    network::netconnect::real_main($o->{net}, $o, $o->{modules_conf});
    require install::interactive;
    install::interactive::upNetwork($o);
    sleep(3);
}

sub ask_url {
    my ($in, $o_url) = @_;

    my $url = $o_url;
    $in->ask_from_({ messages => N("URL of the mirror?"), focus_first => 1 }, [ 
	{ val => \$url,
	  validate => sub { 
	      if ($url =~ m!^(http|ftp)://!) {
		  1;
	      } else {
		  $in->ask_warn('', N("URL must start with ftp:// or http://"));
		  0;
	      }
	  } } ]) && $url;
}
sub ask_mirror {
    my ($o, $type, $o_url) = @_;
    
    require mirror;

    my $mirrors = eval {
	my $_w = $o->wait_message('', N("Contacting Mandriva Linux web site to get the list of available mirrors..."));
	mirror::list($o->{product_id}, $type);
    };
    my $err = $@;
    if (!$mirrors) {
	$o->ask_warn('', N("Failed contacting Mandriva Linux web site to get the list of available mirrors") . "\n$err");
	return ask_url($o, $o_url);
    }

    my $give_url = { country => '-', host => 'URL' };

    my $mirror = $o_url ? (find { $_->{url} eq $o_url } @$mirrors) || $give_url 
        #- use current time zone to select best mirror
      : mirror::nearest($o->{timezone}{timezone}, $mirrors);

    $o->ask_from_({ messages => N("Choose a mirror from which to get the packages"),
		    cancel => N("Cancel"),
		}, [ { separator => '|',
		       format => \&mirror::mirror2text,
		       list => [ @$mirrors, $give_url ],
		       val => \$mirror,
		   },
		 ]) or return;

    my $url;
    if ($mirror eq $give_url) {
	$url = ask_url($o, $o_url) or goto &ask_mirror;
    } else {
	$url = $mirror->{url};
    }
    $url =~ s!/main/?$!!;
    log::l("chosen mirror: $url");
    $url;
}

sub ask_suppl_media_url {
    my ($o, $method, $o_url) = @_;

    if ($method eq 'ftp' || $method eq 'http') {
	install::any::ask_mirror($o, 'distrib', $o_url);
    } elsif ($method eq 'cdrom') {
	'cdrom://';
    } elsif ($method eq 'nfs') {
	my ($host, $dir) = $o_url ? $o_url =~ m!nfs://(.*?)(/.*)! : ();
	$o->ask_from_(
	    { title => N("NFS setup"), 
	      messages => N("Please enter the hostname and directory of your NFS media"),
	      focus_first => 1,
	      callbacks => {
		  complete => sub {
		      $host or $o->ask_warn('', N("Hostname missing")), return 1, 0;
		      $dir eq '' || begins_with($dir, '/') or $o->ask_warn('', N("Directory must begin with \"/\"")), return 1, 1;
		      0;
		  },
	      } },
	    [ { label => N("Hostname of the NFS mount ?"), val => \$host }, 
	      { label => N("Directory"), val => \$dir } ],
	) or return;
	$dir =~ s!/+$!!; 
	$dir ||= '/';
	"nfs://$host$dir";
    } else { internal_error("bad method $method") }
}
sub selectSupplMedia {
    my ($o) = @_;
    my $url;

  ask_method:
    my $method = ask_suppl_media_method($o) or return;

    #- configure network if needed
    if (!scalar keys %{$o->{net}{ifcfg}} && $method !~ /^(?:cdrom|disk)/ && !$::local_install) {
	prep_net_suppl_media($o);
    }

  ask_url:
    $url = ask_suppl_media_url($o, $method, $url) or goto ask_method;

    my $phys_medium = install::media::url2mounted_phys_medium($o, $url, undef, N("Supplementary")) or $o->ask_warn('', formatError($@)), goto ask_url;
    $phys_medium->{is_suppl} = 1;
    $phys_medium->{unknown_CD} = 1;

    my $arch = $o->{product_id}{arch};
    my $field = $phys_medium->{device} ? 'rel_path' : 'url';
    my $val = $phys_medium->{$field};
    my $val0 = $val =~ m!^(.*?)(/media)?/?$! && "$1/media";
    my $val2 = $val =~ m!^(.*?)(/\Q$arch\E)?(/media)?/?$! && "$1/$arch/media";

    foreach (uniq($val0, $val, $val2)) {
	log::l("trying with $field set to $_");
	$phys_medium->{$field} = $_;

	#- first, try to find a media.cfg file
	eval { install::media::get_media_cfg($o, $phys_medium, $o->{packages}, undef, 'force_rpmsrate') };
	if (!$@) {
	    delete $phys_medium->{unknown_CD}; #- we have a known CD now
	    return 1;
	}
    }
    #- restore it
    $phys_medium->{$field} = $val;

    #- try using media_info/hdlist.cz
    my $medium_id = int(@{$o->{packages}{media}});
    eval { install::media::get_standalone_medium($o, $phys_medium, $o->{packages}, { name => "Supplementary media $medium_id" }) };
    if (!$@) {
	log::l("read suppl hdlist (via $method)");
	delete $phys_medium->{unknown_CD}; #- we have a known CD now
	return 1;
    }

    install::media::umount_phys_medium($phys_medium);
    install::media::remove_from_fstab($o->{all_hds}, $phys_medium);
    $o->ask_warn('', N("Can't find a package list file on this mirror. Make sure the location is correct."));
    goto ask_url;
}

sub load_rate_files {
    my ($o) = @_;
    #- must be done after getProvides

    install::pkgs::read_rpmsrate($o->{packages}, $o->{rpmsrate_flags_chosen}, '/tmp/rpmsrate', $o->{match_all_hardware});

    ($o->{compssUsers}, $o->{gtk_display_compssUsers}) = install::pkgs::readCompssUsers('/tmp/compssUsers.pl');

    defined $o->{compssUsers} or die "Can't read compssUsers.pl file, aborting installation\n";
}

sub setPackages {
    my ($o) = @_;

    require install::pkgs;
    {
	$o->{packages} = install::pkgs::empty_packages();
	
	my $media = $o->{media} || [ { type => 'media_cfg', url => 'drakx://media' } ];

	my ($suppl_method, $copy_rpms_on_disk) = install::media::get_media($o, $media, $o->{packages});

	if ($suppl_method) {
	    1 while $o->selectSupplMedia;
	}

	#- open rpm db according to right mode needed (ie rebuilding database if upgrading)
	$o->{packages}{rpmdb} ||= install::pkgs::rpmDbOpen($o->{isUpgrade}, $o->{rpm_dbapi});

	{
	    my $_wait = $o->wait_message('', N("Looking at packages already installed..."));
	    install::pkgs::selectPackagesAlreadyInstalled($o->{packages});
	}

	if (my $extension = $o->{upgrade_by_removing_pkgs_matching}) {
	    my $time = time();
	    my ($_w, $wait_message) = $o->wait_message_with_progress_bar;
	    $wait_message->(N("Removing packages prior to upgrade..."));
	    my ($current, $total);
	    my $callback = sub {
		my (undef, $type, $_id, $subtype, $amount) = @_;
		if ($type eq 'user') {
		    ($current, $total) = (0, $amount);
		} elsif ($type eq 'uninst' && $subtype eq 'stop') {
		    $wait_message->('', $current++, $total);
		}
	    };
	    push @{$o->{default_packages}}, install::pkgs::upgrade_by_removing_pkgs($o->{packages}, $callback, $extension, $o->{isUpgrade});
	    log::l("Removing packages took: ", formatTimeRaw(time() - $time));
	}

	mark_skipped_packages($o);

	#- always try to select basic kernel (else on upgrade, kernel will never be updated provided a kernel is already
	#- installed and provides what is necessary).
	my $kernel_pkg = install::pkgs::bestKernelPackage($o->{packages});
	install::pkgs::selectPackage($o->{packages}, $kernel_pkg, 1);
	if ($o->{isUpgrade} && $o->{packages}{sizes}{dkms}) {
	    log::l("selecting kernel-desktop-devel-latest (since dkms was installed)");
	    install::pkgs::select_by_package_names($o->{packages}, ['kernel-desktop-devel-latest'], 1);
	}

	install::pkgs::select_by_package_names_or_die($o->{packages}, ['basesystem'], 1);

	my $rpmsrate_flags_was_chosen = $o->{rpmsrate_flags_chosen};

	put_in_hash($o->{rpmsrate_flags_chosen} ||= {}, rpmsrate_always_flags($o)); #- must be done before install::pkgs::read_rpmsrate()
	load_rate_files($o);

	install::media::copy_rpms_on_disk($o) if $copy_rpms_on_disk;

	set_rpmsrate_default_category_flags($o, $rpmsrate_flags_was_chosen);

	push @{$o->{default_packages}}, default_packages($o);
	select_default_packages($o);
    }

    if ($o->{isUpgrade}) {
	{
	    my $_w = $o->wait_message('', N("Finding packages to upgrade..."));
	    install::pkgs::selectPackagesToUpgrade($o->{packages});
	}
	if ($o->{packages}{sizes}{'kdebase-progs'}) {
	    log::l("selecting task-kde (since kdebase-progs was installed)");
	    install::pkgs::select_by_package_names($o->{packages}, ['task-kde']);
	}
    }
}

sub create_minimal_files() {
    mkdir "$::prefix/$_", 0755 foreach 
      qw(dev etc etc/profile.d etc/rpm etc/sysconfig etc/sysconfig/console 
	etc/sysconfig/network-scripts etc/sysconfig/console/consolefonts 
	etc/sysconfig/console/consoletrans
	home mnt tmp var var/tmp var/lib var/lib/rpm var/lib/urpmi);
    mkdir "$::prefix/$_", 0700 foreach qw(root root/tmp root/drakx);

    devices::make("$::prefix/dev/null");
    chmod 0666, "$::prefix/dev/null";
}

sub count_files {
    my ($dir) = @_;
    -d $dir or return 0;
    opendir my $dh, $dir or return 0;
    my @list = grep { !/^\.\.?$/ } readdir $dh;
    closedir $dh;
    my $c = 0;
    foreach my $n (@list) {
	my $p = "$dir/$n";
	if (-d $p) { $c += count_files($p) } else { ++$c }
    }
    $c;
}

sub cp_with_progress {
    my $wait_message = shift;
    my $current = shift;
    my $total = shift;
    my $dest = pop @_;
    @_ or return;
    @_ == 1 || -d $dest or die "cp: copying multiple files, but last argument ($dest) is not a directory\n";

    foreach my $src (@_) {
	my $dest = $dest;
	-d $dest and $dest .= '/' . basename($src);

	unlink $dest;

	if (-l $src) {
	    unless (symlink(readlink($src) || die("readlink failed: $!"), $dest)) {
		warn "symlink: can't create symlink $dest: $!\n";
	    }
	} elsif (-d $src) {
	    -d $dest or mkdir $dest, (stat($src))[2] or die "mkdir: can't create directory $dest: $!\n";
	    cp_with_progress($wait_message, $current, $total, glob_($src), $dest);
	} else {
	    open(my $F, $src) or die "can't open $src for reading: $!\n";
	    open(my $G, ">", $dest) or die "can't cp to file $dest: $!\n";
	    local $/ = \4096;
	    local $_; while (<$F>) { print $G $_ }
	    chmod((stat($src))[2], $dest);
	    $wait_message->('', ++$current, $total);
	}
    }
    1;
}

sub set_rpmsrate_default_category_flags {
    my ($o, $rpmsrate_flags_was_chosen) = @_;

    #- if no cleaning needed, populate by default, clean is used for second or more call to this function.
    if ($::auto_install && ($o->{rpmsrate_flags_chosen} || {})->{CAT_ALL}) {
	$o->{rpmsrate_flags_chosen}{"CAT_$_"} = 1 foreach map { @{$_->{flags}} } @{$o->{compssUsers}};
    }
    if (!$rpmsrate_flags_was_chosen && !$o->{isUpgrade}) {
	#- use default selection seen in compssUsers directly.
	$_->{selected} = $_->{default_selected} foreach @{$o->{compssUsers}};
	set_rpmsrate_category_flags($o, $o->{compssUsers});
    }
}

sub set_rpmsrate_category_flags {
    my ($o, $compssUsers) = @_;

    $o->{rpmsrate_flags_chosen}{$_} = 0 foreach grep { /^CAT_/ } keys %{$o->{rpmsrate_flags_chosen}};
    $o->{rpmsrate_flags_chosen}{"CAT_$_"} = 1 foreach map { @{$_->{flags}} } grep { $_->{selected} } @$compssUsers;
    $o->{rpmsrate_flags_chosen}{CAT_SYSTEM} = 1;
    $o->{rpmsrate_flags_chosen}{CAT_MINIMAL_DOCS} = 1;
}


sub rpmsrate_always_flags {
    my ($o) = @_;

    my $rpmsrate_flags_chosen = {};
    $rpmsrate_flags_chosen->{qq(META_CLASS"$o->{meta_class}")} = 1;
    $rpmsrate_flags_chosen->{uc($_)} = 1 foreach grep { $o->{match_all_hardware} || detect_devices::probe_category("multimedia/$_") } modules::sub_categories('multimedia');
    $rpmsrate_flags_chosen->{uc($_)} = 1 foreach detect_devices::probe_name('Flag');
    $rpmsrate_flags_chosen->{UTF8} = $o->{locale}{utf8};
    $rpmsrate_flags_chosen->{BURNER} = 1 if $o->{match_all_hardware} || detect_devices::burners();
    $rpmsrate_flags_chosen->{DVD} = 1 if $o->{match_all_hardware} || detect_devices::dvdroms();
    $rpmsrate_flags_chosen->{USB} = 1 if $o->{match_all_hardware} || $o->{modules_conf}->get_probeall("usb-interface");
    $rpmsrate_flags_chosen->{PCMCIA} = 1 if $o->{match_all_hardware} || detect_devices::hasPCMCIA();
    $rpmsrate_flags_chosen->{HIGH_SECURITY} = 1 if $o->{security} > 3;
    $rpmsrate_flags_chosen->{BIGMEM} = 1 if detect_devices::BIGMEM();
    $rpmsrate_flags_chosen->{SMP} = 1 if detect_devices::hasSMP();
    $rpmsrate_flags_chosen->{CDCOM} = 1 if any { $_->{name} =~ /commercial/i } install::media::allMediums($o->{packages});
    $rpmsrate_flags_chosen->{'3D'} = 1 if
      $o->{match_all_hardware} ||
      detect_devices::matching_desc__regexp('Matrox.* G[245][05]0') ||
      detect_devices::matching_desc__regexp('Rage X[CL]') ||
      detect_devices::matching_desc__regexp('3D Rage (?:LT|Pro)') ||
      detect_devices::matching_desc__regexp('Voodoo [35]') ||
      detect_devices::matching_desc__regexp('Voodoo Banshee') ||
      detect_devices::matching_desc__regexp('8281[05].* CGC') ||
      detect_devices::matching_desc__regexp('Rage 128') ||
      detect_devices::matching_desc__regexp('Radeon ') || #- all Radeon card are now 3D with 4.3.0
      detect_devices::matching_desc__regexp('[nN]Vidia.*T[nN]T2') || #- TNT2 cards
      detect_devices::matching_desc__regexp('[nN][vV]idia.*NV[56]') ||
      detect_devices::matching_desc__regexp('[nN][vV]idia.*Vanta') ||
      detect_devices::matching_desc__regexp('[nN][vV]idia.*[gG]e[fF]orce') || #- GeForce cards
      detect_devices::matching_desc__regexp('[nN][vV]idia.*NV1[15]') ||
      detect_devices::matching_desc__regexp('[nN][vV]idia.*Quadro');

    foreach (lang::langsLANGUAGE($o->{locale}{langs})) {
	$rpmsrate_flags_chosen->{qq(LOCALES"$_")} = 1;
    }
    $rpmsrate_flags_chosen->{'CHARSET"' . lang::l2charset($o->{locale}{lang}) . '"'} = 1;

    $rpmsrate_flags_chosen;
}

sub default_packages {
    my ($o) = @_;
    my @l;

    push @l, "brltty" if cat_("/proc/cmdline") =~ /brltty=/;
    push @l, "nfs-utils-clients" if $o->{method} eq "nfs";
    push @l, "mdadm" if !is_empty_array_ref($o->{all_hds}{raids});
    push @l, "lvm2" if !is_empty_array_ref($o->{all_hds}{lvms});
    push @l, "dmraid" if any { fs::type::is_dmraid($_) } @{$o->{all_hds}{hds}};
    push @l, 'powernowd' if cat_('/proc/cpuinfo') =~ /AuthenticAMD/ && arch() =~ /x86_64/
      || cat_('/proc/cpuinfo') =~ /model name.*Intel\(R\) Core\(TM\)2 CPU/;
    push @l, detect_devices::probe_name('Pkg');

    my $dmi_BIOS = detect_devices::dmidecode_category('BIOS');
    my $dmi_Base_Board = detect_devices::dmidecode_category('Base Board');
    if ($dmi_BIOS->{Vendor} eq 'COMPAL' && $dmi_BIOS->{Characteristics} =~ /Function key-initiated network boot is supported/
          || $dmi_Base_Board->{Manufacturer} =~ /^ACER/ && $dmi_Base_Board->{'Product Name'} =~ /TravelMate 610/) {
	#- FIXME : append correct options (wireless, ...)
	modules::append_to_modules_loaded_at_startup_for_all_kernels('acerhk');
    }

    push @l, 'quota' if any { $_->{options} =~ /usrquota|grpquota/ } @{$o->{fstab}};
    push @l, uniq(grep { $_ } map { fs::format::package_needed_for_partition_type($_) } @{$o->{fstab}});

    my @locale_pkgs = map { install::pkgs::packagesProviding($o->{packages}, 'locales-' . $_) } lang::langsLANGUAGE($o->{locale}{langs});
    unshift @l, uniq(map { $_->name } @locale_pkgs);

    @l;
}

sub mark_skipped_packages {
    my ($o) = @_;
    install::pkgs::skip_packages($o->{packages}, $o->{skipped_packages}) if $o->{skipped_packages};
}

sub select_default_packages {
    my ($o) = @_;
    install::pkgs::select_by_package_names($o->{packages}, $o->{default_packages});
}

sub unselectMostPackages {
    my ($o) = @_;
    install::pkgs::unselectAllPackages($o->{packages});
    select_default_packages($o);
}

sub warnAboutNaughtyServers {
    my ($o) = @_;
    my @naughtyServers = install::pkgs::naughtyServers($o->{packages}) or return 1;
    my $r = $o->ask_from_list_('', 
formatAlaTeX(
             #-PO: keep the double empty lines between sections, this is formatted a la LaTeX
             N("You have selected the following server(s): %s


These servers are activated by default. They do not have any known security
issues, but some new ones could be found. In that case, you must make sure
to upgrade as soon as possible.


Do you really want to install these servers?
", join(", ", @naughtyServers))), [ N_("Yes"), N_("No") ], 'Yes') or return;
    if ($r ne 'Yes') {
	log::l("unselecting naughty servers: " . join(' ', @naughtyServers));
	install::pkgs::unselectPackage($o->{packages}, install::pkgs::packageByName($o->{packages}, $_)) foreach @naughtyServers;
    }
    1;
}

sub warnAboutRemovedPackages {
    my ($o, $packages) = @_;
    my @removedPackages = keys %{$packages->{state}{ask_remove} || {}} or return;
    if (!$o->ask_yesorno('', 
formatAlaTeX(
             #-PO: keep the double empty lines between sections, this is formatted a la LaTeX
             N("The following packages will be removed to allow upgrading your system: %s


Do you really want to remove these packages?
", join(", ", @removedPackages))), 1)) {
	$packages->{state}{ask_remove} = {};
    }
}

sub addToBeDone(&$) {
    my ($f, $step) = @_;

    return &$f() if $::o->{steps}{$step}{done};

    push @{$::o->{steps}{$step}{toBeDone}}, $f;
}

sub set_authentication {
    my ($o) = @_;

    my $when_network_is_up = sub {
	my ($f) = @_;
	#- defer running xxx - no network yet
	addToBeDone {
	    require install::steps;
	    install::steps::upNetwork($o, 'pppAvoided');
	    $f->();
	} 'configureNetwork';
    };
    require authentication;
    authentication::set($o, $o->{net}, $o->{authentication} ||= {}, $when_network_is_up);
}

#-###############################################################################
#- kde stuff
#-###############################################################################
sub kdemove_desktop_file {
    my ($prefix) = @_;
    my @toMove = qw(doc.kdelnk news.kdelnk updates.kdelnk home.kdelnk printer.kdelnk floppy.kdelnk cdrom.kdelnk FLOPPY.kdelnk CDROM.kdelnk);

    #- remove any existing save in Trash of each user and
    #- move appropriate file there after an upgrade.
    foreach my $dir (grep { -d $_ } list_skels($prefix, 'Desktop')) {
	renamef("$dir/$_", "$dir/Trash/$_") 
	  foreach grep { -e "$dir/$_" } @toMove, grep { /\.rpmorig$/ } all($dir);
    }
}


#-###############################################################################
#- auto_install stuff
#-###############################################################################
sub auto_inst_file() { "$::prefix/root/drakx/auto_inst.cfg.pl" }

sub report_bug() {
    any::report_bug('auto_inst' => g_auto_install('', 1));
}

sub g_auto_install {
    my ($b_replay, $b_respect_privacy) = @_;
    my $o = {};

    require install::pkgs;
    $o->{default_packages} = install::pkgs::selected_leaves($::o->{packages});

    my @fields = qw(mntpoint fs_type size);
    $o->{partitions} = [ map { 
	my %l; @l{@fields} = @$_{@fields}; \%l;
    } grep { 
	$_->{mntpoint} && fs::format::known_type($_);
    } @{$::o->{fstab}} ];
    
    exists $::o->{$_} and $o->{$_} = $::o->{$_} foreach qw(locale authentication mouse net timezone superuser keyboard users partitioning isUpgrade manualFstab nomouseprobe crypto security security_user libsafe autoExitInstall X services postInstall postInstallNonRooted); #- TODO modules bootloader 

    local $o->{partitioning}{auto_allocate} = !$b_replay;
    $o->{autoExitInstall} = !$b_replay;
    $o->{interactiveSteps} = [ 'doPartitionDisks', 'formatPartitions' ] if $b_replay;

    #- deep copy because we're modifying it below
    $o->{users} = $b_respect_privacy ? [] : [ @{$o->{users} || []} ];

    my @user_info_to_remove = (
	if_($b_respect_privacy, qw(realname pw)), 
	qw(oldu oldg password password2),
    );
    $_ = { %{$_ || {}} }, delete @$_{@user_info_to_remove} foreach $o->{superuser}, @{$o->{users} || []};

    if ($b_respect_privacy && $o->{net}) {
	if (my $type = $o->{net}{type}) {
	    my @net_type_to_remove = qw(passwd login phone_in phone_out);
	    $_ = { %{$_ || {}} }, delete @$_{@net_type_to_remove} foreach $o->{net}{$type};
	}
    }
    my $warn_privacy = $b_respect_privacy ? "!! This file has been simplified to respect privacy when reporting problems.
# You should use /root/drakx/auto_inst.cfg.pl instead !!\n#" : '';
    
    require Data::Dumper;
    my $str = join('', 
"#!/usr/bin/perl -cw
# $warn_privacy
# You should check the syntax of this file before using it in an auto-install.
# You can do this with 'perl -cw auto_inst.cfg.pl' or by executing this file
# (note the '#!/usr/bin/perl -cw' on the first line).
", Data::Dumper->Dump([$o], ['$o']));
    $str =~ s/ {8}/\t/g; #- replace all 8 space char by only one tabulation, this reduces file size so much :-)
    $str;
}

sub getAndSaveAutoInstallFloppies {
    my ($o, $replay) = @_;
    my $name = ($replay ? 'replay' : 'auto') . '_install';
    my $dest_dir = "$::prefix/root/drakx";

    eval { modules::load('loop') };

    if (arch() =~ /ia64/) {
	#- nothing yet
    } else {
	my $mountdir = "$::prefix/root/aif-mount"; -d $mountdir or mkdir $mountdir, 0755;
	my $param = 'kickstart=floppy ' . generate_automatic_stage1_params($o);

	my $img = install::media::getAndSaveInstallFloppies($o, $dest_dir, $name) or return;

	{
	    my $dev = devices::set_loop($img) or log::l("couldn't set loopback device"), return;
	    find { eval { fs::mount::mount($dev, $mountdir, $_, 0); 1 } } qw(ext2 vfat) or return;

	    if (-e "$mountdir/menu.lst") {
		# hd_grub boot disk is different than others
		substInFile {
		    s/^(\s*timeout.*)/timeout 1/;
		    s/\bautomatic=method:disk/$param/;
		} "$mountdir/menu.lst";
	    } elsif (-e "$mountdir/syslinux.cfg") {
		#- make room first
		unlink "$mountdir/help.msg", "$mountdir/boot.msg";

		substInFile { 
		    s/timeout.*/$replay ? 'timeout 1' : ''/e;
		    s/^(\s*append)/$1 $param/; 
		} "$mountdir/syslinux.cfg";

		output "$mountdir/boot.msg", $replay ? '' : "\n0c" .
"!! If you press enter, an auto-install is going to start.
   All data on this computer is going to be lost,
   including any Windows partitions !!
" . "07\n";
	    }

	    {
		local $o->{partitioning}{clearall} = !$replay;
		eval { output("$mountdir/auto_inst.cfg", g_auto_install($replay)) };
		$@ and log::l("Warning: <", formatError($@), ">");
	    }
	
	    fs::mount::umount($mountdir);
	    devices::del_loop($dev);
	}
	rmdir $mountdir;
	$img;
    }
}


sub g_default_packages {
    my ($o) = @_;

    my ($_h, $file) = media_browser($o, 'save', 'package_list.pl') or return;

    require Data::Dumper;
    my $str = Data::Dumper->Dump([ { default_packages => install::pkgs::selected_leaves($o->{packages}) } ], ['$o']);
    $str =~ s/ {8}/\t/g;
    output($file,
	   "# You should always check the syntax with 'perl -cw auto_inst.cfg.pl'\n" .
	   "# before testing.  To use it, boot with ``linux defcfg=floppy''\n" .
	   $str);
}

sub loadO {
    my ($O, $f) = @_; $f ||= auto_inst_file();
    if ($f =~ /^(floppy|patch)$/) {
	my $f = $f eq "floppy" ? 'auto_inst.cfg' : "patch";
	my $o;
	foreach (removable_media__early_in_install()) {
            my $dev = devices::make($_->{device});
            foreach my $fs (arch() =~ /sparc/ ? 'romfs' : ('ext2', 'vfat')) {
                eval { fs::mount::mount($dev, '/mnt', $fs, 'readonly'); 1 } or next;
		if (my $abs_f = find { -e $_ } "/mnt/$f", "/mnt/$f.pl") {
		    $o = loadO_($O, $abs_f);
		}
		fs::mount::umount("/mnt");
		goto found if $o;
            }
	}
	die "Could not find $f";
      found:
	modules::unload(qw(vfat fat));
	$o;
    } else {
	loadO_($O, $f);
    }
}

sub loadO_ {
    my ($O, $f) = @_; 

    my $o;
    {
	my $fh;
	if (ref $f) {
	    $fh = $f;
	} else {
	    -e "$f.pl" and $f .= ".pl" unless -e $f;

	    $fh = -e $f ? common::open_file($f) : getFile_($O->{stage2_phys_medium}, $f) || die N("Error reading file %s", $f);
	}
	my $s = cat__($fh);
	close $fh;
	{
	    no strict;
	    eval $s;
	    $@ and die;
	}
	$O and add2hash_($o ||= {}, $O);
    }
    $O and bless $o, ref $O;

    handle_old_auto_install_format($o);

    $o;
}

sub handle_old_auto_install_format {
    my ($o) = @_;

    #- handle backward compatibility for things that changed
    foreach (@{$o->{partitions} || []}, @{$o->{manualFstab} || []}) {
	if (my $type = delete $_->{type}) {
	    if ($type =~ /^(0x)?(\d*)$/) {
		fs::type::set_pt_type($_, $type);
	    } else {
		fs::type::set_fs_type($_, $type);
	    }
	}
    }
    #- {rpmsrate_flags_chosen} was called {compssUsersChoice}
    if (my $rpmsrate_flags_chosen = delete $o->{compssUsersChoice}) {
	$o->{rpmsrate_flags_chosen} = $rpmsrate_flags_chosen;
    }
    #- compssUsers flags are now named CAT_XXX
    if ($o->{rpmsrate_flags_chosen} &&
	! any { /^CAT_/ } keys %{$o->{rpmsrate_flags_chosen}}) {
	#- we don't really know if this is needed for compatibility, but it won't hurt :)
	foreach (keys %{$o->{rpmsrate_flags_chosen}}) {
	    $o->{rpmsrate_flags_chosen}{"CAT_$_"} = $o->{rpmsrate_flags_chosen}{$_};
	}
	#- it used to be always selected
	$o->{rpmsrate_flags_chosen}{CAT_SYSTEM} = 1;
    }
    if ($o->{updates} && $o->{updates}{mirror}) {
	$o->{updates}{url} = delete $o->{updates}{mirror};
    }

    #- backward compatibility for network fields
    exists $o->{intf} and $o->{net}{ifcfg} = delete $o->{intf};
    exists $o->{netcnx}{type} and $o->{net}{type} = delete $o->{netcnx}{type};
    exists $o->{netc}{NET_INTERFACE} and $o->{net}{net_interface} = delete $o->{netc}{NET_INTERFACE};
    my %netc_translation = (
			    resolv => [ qw(dnsServer dnsServer2 dnsServer3 DOMAINNAME DOMAINNAME2 DOMAINNAME3) ],
			    network => [ qw(NETWORKING FORWARD_IPV4 NETWORKING_IPV6 HOSTNAME GATEWAY GATEWAYDEV NISDOMAIN) ],
			    auth => [ qw(LDAPDOMAIN WINDOMAIN) ],
			   );
    foreach my $dest (keys %netc_translation) {
	exists $o->{netc}{$_} and $o->{net}{$dest}{$_} = delete $o->{netc}{$_} foreach @{$netc_translation{$dest}};
    }
    delete @$o{qw(netc netcnx)};

    $o;
}

sub generate_automatic_stage1_params {
    my ($o) = @_;

    my $method = $o->{method};
    my @ks;

    if ($o->{method} eq 'http') {
	$ENV{URLPREFIX} =~ m!(http|ftp)://([^/:]+)(.*)! or die;
	$method = $1; #- in stage1, FTP via HTTP proxy is available through FTP config, not HTTP
	@ks = (server => $2, directory => $3);
    } elsif ($o->{method} eq 'ftp') {
	my @l = install::ftp::parse_ftp_url($ENV{URLPREFIX});
	@ks = (server => $l[0], directory => $l[1], user => $l[2], pass => $l[3]);
    } elsif ($o->{method} eq 'nfs') {
	cat_("/proc/mounts") =~ m|(\S+):(\S+)\s+/tmp/media| or internal_error("can not find nfsimage");
	@ks = (server => $1, directory => $2);
    }
    @ks = (method => $method, @ks);

    if (is_network_install($o)) {
	if ($ENV{PROXY}) {
	    push @ks, proxy_host => $ENV{PROXY}, proxy_port => $ENV{PROXYPORT};
	}
	my $intf = first(values %{$o->{net}{ifcfg}});
	push @ks, interface => $intf->{DEVICE};
	if ($intf->{BOOTPROTO} eq 'dhcp') {
	    push @ks, network => 'dhcp';
	} else {
	    push @ks, network => 'static', ip => $intf->{IPADDR}, netmask => $intf->{NETMASK}, gateway => $o->{net}{network}{GATEWAY};
	    require network::network;
	    if (my @dnss = network::network::dnsServers($o->{net})) {
		push @ks, dns => $dnss[0];
	    }
	}
    }

    #- sync it with ../mdk-stage1/automatic.c
    my %aliases = (method => 'met', network => 'netw', interface => 'int', gateway => 'gat', netmask => 'netm',
		   adsluser => 'adslu', adslpass => 'adslp', hostname => 'hos', domain => 'dom', server => 'ser',
		   directory => 'dir', user => 'use', pass => 'pas', disk => 'dis', partition => 'par');
    
    'automatic=' . join(',', map { ($aliases{$_->[0]} || $_->[0]) . ':' . $_->[1] } group_by2(@ks));
}

sub find_root_parts {
    my ($fstab, $prefix) = @_;

    my $extract = sub {
	my ($prefix, $f, $part) = @_;
	chomp(my $s = cat_("$prefix$f"));
	$s =~ s/\s+for\s+\S+//;
	log::l("find_root_parts found $part->{device}: $s" . ($f !~ m!/etc/! ? " in special release file $f" : ''));
	{ release => $s, release_file => $f, part => $part };
    };

    if ($::local_install) {
	my $f = common::release_file('/mnt') or return;
	return $extract->('/mnt', $f, {});
    }

    map { 
	my $handle = any::inspect($_, $prefix);
	if (my $f = $handle && common::release_file($handle->{dir})) {
	    $extract->($handle->{dir}, $f, $_);
	} else { () }
    } grep { isTrueLocalFS($_) } @$fstab;
}

sub migrate_device_names {
    my ($all_hds, $from_fstab, $new_root, $root_from_fstab, $o_in) = @_;

    log::l("warning: fstab says root partition is $root_from_fstab->{device}, whereas we were reading fstab from $new_root->{device}");
    my ($old_prefix, $old_part_number) = devices::simple_partition_scan($root_from_fstab);
    my ($new_prefix, $new_part_number) = devices::simple_partition_scan($new_root);

    if ($old_part_number != $new_part_number) {
	log::l("argh, $root_from_fstab->{device} and $old_part_number->{device} are not the same partition number");
	return;
    }

    log::l("replacing $old_prefix with $new_prefix");
    
    my %h;
    foreach (@$from_fstab) {
	if ($_->{device} =~ s!^\Q$old_prefix!$new_prefix!) {
	    #- this is simple to handle, nothing more to do
	} elsif ($_->{part_number}) {
	    my $device_prefix = devices::part_prefix($_);
	    push @{$h{$device_prefix}}, $_;
	} else {
	    #- hopefully this does not need anything special
	}
    }
    my @from_fstab_per_hds = values %h or return;


    my @current_hds = grep { $new_root->{rootDevice} ne $_->{device} } fs::get::hds($all_hds);

    found_one:
    @from_fstab_per_hds or return;

    foreach my $from_fstab_per_hd (@from_fstab_per_hds) {
	my ($matching, $other) = partition { 
	    my $hd = $_;
	    every {
		my $wanted = $_;
		my $part = find { $_->{part_number} eq $wanted->{part_number} } partition_table::get_normal_parts($hd);
		$part && $part->{fs_type} && fs::type::can_be_this_fs_type($wanted, $part->{fs_type});
	    } @$from_fstab_per_hd;
	} @current_hds;
	@$matching == 1 or next;

	my ($hd) = @$matching;
	@current_hds = @$other;
	@from_fstab_per_hds = grep { $_ != $from_fstab_per_hd } @from_fstab_per_hds;

	log::l("$hd->{device} nicely corresponds to " . join(' ', map { $_->{device} } @$from_fstab_per_hd));
	foreach (@$from_fstab_per_hd) {
	    partition_table::compute_device_name($_, $hd);
	}
	goto found_one;
    }
	
    #- we can not find one and only one matching hd
    my @from_fstab_not_handled = map { @$_ } @from_fstab_per_hds;
    log::l("we still do not know what to do with: " . join(' ', map { $_->{device} } @from_fstab_not_handled));


    if (!$o_in) {
	log::l("well, ignoring them!");
	return;
    }

    my $propositions_valid = every {
	my $wanted = $_;
	my @parts = grep { $_->{part_number} eq $wanted->{part_number}
			     && $_->{fs_type} && fs::type::can_be_this_fs_type($wanted, $_->{fs_type}) } fs::get::hds_fstab(@current_hds);
	$wanted->{propositions} = \@parts;
	@parts > 0;
    } @from_fstab_not_handled;

    $o_in->ask_from('', 
		    N("The following disk(s) were renamed:"),
		    [ map {
			{ label => N("%s (previously named as %s)", $_->{mntpoint}, $_->{device}),
			  val => \$_->{device}, format => sub { $_[0] && $_->{device} },
			  list => [ '', 
				    $propositions_valid ? @{$_->{propositions}} : 
				    fs::get::hds_fstab(@current_hds) ] };
		    } @from_fstab_not_handled ]);
}

sub use_root_part {
    my ($all_hds, $part, $o_in) = @_;
    return if $::local_install;

    my $migrate_device_names;
    {
	my $handle = any::inspect($part, $::prefix) or internal_error();

	my @from_fstab = fs::read_fstab($handle->{dir}, '/etc/fstab', 'keep_default');

	my $root_from_fstab = fs::get::root_(\@from_fstab);
	if (!fs::get::is_same_hd($root_from_fstab, $part)) {
	    $migrate_device_names = 1;
	    log::l("from_fstab contained: $_->{device} $_->{mntpoint}") foreach @from_fstab;
	    migrate_device_names($all_hds, \@from_fstab, $part, $root_from_fstab, $o_in);
	    log::l("from_fstab now contains: $_->{device} $_->{mntpoint}") foreach @from_fstab;
	}
	fs::add2all_hds($all_hds, @from_fstab);
	log::l("fstab is now: $_->{device} $_->{mntpoint}") foreach fs::get::fstab($all_hds);
    }
    isSwap($_) and $_->{mntpoint} = 'swap' foreach fs::get::really_all_fstab($all_hds); #- use all available swap.
    $migrate_device_names;
}

sub getHds {
    my ($o, $o_in) = @_;
    fs::any::get_hds($o->{all_hds} ||= {}, $o->{fstab} ||= [], 
		     $o->{manualFstab}, $o->{partitioning}, $::local_install, $o_in);
}

sub removable_media__early_in_install() {
    eval { modules::load('usb_storage', 'sd_mod') } if detect_devices::usbStorage();
    my $all_hds = fsedit::get_hds({});
    fs::get_raw_hds('', $all_hds);

    my @l1 = grep { detect_devices::isKeyUsb($_) } @{$all_hds->{hds}};
    my @l2 = grep { $_->{media_type} eq 'fd' || detect_devices::isKeyUsb($_) } @{$all_hds->{raw_hds}};
    (fs::get::hds_fstab(@l1), @l2);
}

my %media_browser;
sub media_browser {
    my ($in, $save, $o_suggested_name) = @_;

    my %media_type2text = (
	fd => N("Floppy"),
	hd => N("Hard Disk"),
	cdrom => N("CDROM"),
    );
    my @network_protocols = (if_(!$save, N_("HTTP")), if_(0, N_("FTP")), N_("NFS"));

    my $to_text = sub {
	my ($hd) = @_;
	($media_type2text{$hd->{media_type}} || $hd->{media_type}) . ': ' . partition_table::description($hd);
    };

  ask_media:
    my $all_hds = fsedit::get_hds({}, $in);
    fs::get_raw_hds('', $all_hds);

    my @raw_hds = grep { !$save || $_->{media_type} ne 'cdrom' } @{$all_hds->{raw_hds}};
    my @dev_and_text = group_by2(
	(map { $_ => $to_text->($_) } @raw_hds),
	(map { 
	    my $hd = $to_text->($_);
	    map { $_ => join('\1', $hd, partition_table::description($_)) } grep { isTrueFS($_) || isOtherAvailableFS($_) } fs::get::hds_fstab($_);
	} fs::get::hds($all_hds)),
	if_(is_network_install($::o) || install::steps::hasNetwork($::o),
	    map { $_ => join('\1', N("Network"), translate($_)) } @network_protocols),
    );

    $in->ask_from_({
	messages => N("Please choose a media"),
    }, [ 
	{ val => \$media_browser{dev}, separator => '\1', list => [ map { $_->[1] } @dev_and_text ] },
    ]) or return;

    my $dev = (find { $_->[1] eq $media_browser{dev} } @dev_and_text)->[0];

    my $browse = sub {
	my ($dir) = @_;

      browse:
	my $file = $in->ask_filename({ save => $save, 
				       directory => $dir, 
				       if_($o_suggested_name, file => "$dir/$o_suggested_name"),
				   }) or return;
	if (-e $file && $save) {
	    $in->ask_yesorno('', N("File already exists. Overwrite it?")) or goto browse;
	}
	if ($save) {
	    if (!open(my $_fh, ">>$file")) {
		$in->ask_warn('', N("Permission denied"));
		goto browse;
	    }
	    $file;
	} else {
	    common::open_file($file) || goto browse;
	}
    };
    my $inspect_and_browse = sub {
	my ($dev) = @_;

	if (my $h = any::inspect($dev, $::prefix, $save)) {
	    if (my $file = $browse->($h->{dir})) {
		return $h, $file;
	    }
	    undef $h; #- help perl
	} else {
	    $in->ask_warn(N("Error"), formatError($@));
	}
	();
    };

    if (member($dev, @network_protocols)) {
	require install::interactive;
	install::interactive::upNetwork($::o);

	if ($dev eq 'HTTP') {
	    require install::http;
	    $media_browser{url} ||= 'http://';

	    while (1) {
		$in->ask_from('', 'URL', [
		    { val => \$media_browser{url} }
		]) or last;
		    
		if ($dev eq 'HTTP') {
		    my $fh = install::http::getFile($media_browser{url});
		    $fh and return '', $fh;
		}
	    }
	} elsif ($dev eq 'NFS') {
	    while (1) {
		$in->ask_from('', 'NFS', [
		    { val => \$media_browser{nfs} }
		]) or last;

		my ($kind) = fs::wild_device::analyze($media_browser{nfs});
		if ($kind ne 'nfs') {
		    $in->ask_warn('', N("Bad NFS name"));
		    next;
		}

		my $nfs = fs::wild_device::to_subpart($media_browser{nfs});
		$nfs->{fs_type} = 'nfs';

		if (my ($h, $file) = $inspect_and_browse->($nfs)) {
		    return $h, $file;
		}
	    }
	} else {
	    $in->ask_warn('', 'todo');
	    goto ask_media;
	}
    } else {
	if (!$dev->{fs_type} || $dev->{fs_type} eq 'auto' || $dev->{fs_type} =~ /:/) {
	    if (my $p = fs::type::type_subpart_from_magic($dev)) {
		add2hash($p, $dev);
		$dev = $p;
	    } else {
		$in->ask_warn(N("Error"), N("Bad media %s", partition_table::description($dev)));
		goto ask_media;
	    }
	}

	if (my ($h, $file) = $inspect_and_browse->($dev)) {
	    return $h, $file;
	}

	goto ask_media;
    }
}

sub X_options_from_o {
    my ($o) = @_;
    { 
	freedriver => $o->{freedriver},
	allowFB => $o->{allowFB},
	ignore_bad_conf => $o->{isUpgrade} =~ /redhat|conectiva/,
    };
}

sub screenshot_dir__and_move() {
    my ($dir0, $dir1, $dir2) = ('/root', "$::prefix/root", '/tmp');
    if (-e $dir0 && ! -e '/root/non-chrooted-marker.DrakX') {
	$dir0; #- it occurs during pkgs install when we are chrooted
    } elsif (-e $dir1) {
	if (-e "$dir2/DrakX-screenshots") {
	    cp_af("$dir2/DrakX-screenshots", $dir1);
	    rm_rf("$dir2/DrakX-screenshots");
	}
	$dir1;
    } else {
	$dir2;
    }
}

sub take_screenshot {
    my ($in) = @_;
    my $dir = screenshot_dir__and_move() . '/DrakX-screenshots';
    my $warn;
    if (!-e $dir) {
	mkdir $dir or $in->ask_warn('', N("Can not make screenshots before partitioning")), return;
	$warn = 1;
    }
    my $nb = 1;
    $nb++ while -e "$dir/$nb.png";
    system("fb2png /dev/fb0 $dir/$nb.png 0");

    $in->ask_warn('', N("Screenshots will be available after install in %s", "/root/DrakX-screenshots")) if $warn;
}

sub copy_advertising {
    my ($o) = @_;

    return if $::rootwidth < 800;

    my $f;
    my $source_dir = "install/extra/advertising";
    foreach ("." . $o->{locale}{lang}, "." . substr($o->{locale}{lang},0,2), '') {
	$f = getFile_($o->{stage2_phys_medium}, "$source_dir$_/list") or next;
	$source_dir = "$source_dir$_";
    }
    if (my @files = <$f>) {
	my $dir = "$::prefix/tmp/drakx-images";
	mkdir $dir;
	unlink glob_("$dir/*");
	foreach (@files) {
	    chomp;
	    install::media::getAndSaveFile_($o->{stage2_phys_medium}, "$source_dir/$_", "$dir/$_");
	    (my $pl = $_) =~ s/\.png/.pl/;
	    install::media::getAndSaveFile_($o->{stage2_phys_medium}, "$source_dir/$pl", "$dir/$pl");
	}
	@advertising_images = map { "$dir/$_" } @files;
    }
}

sub remove_advertising() {
    eval { rm_rf("$::prefix/tmp/drakx-images") };
    @advertising_images = ();
}

sub disable_user_view() {
    substInFile { s/^UserView=.*/UserView=true/ } "$::prefix/etc/kde/kdm/kdmrc";
    substInFile { s/^Browser=.*/Browser=0/ } "$::prefix/etc/X11/gdm/custom.conf";
}

sub set_security {
    my ($o) = @_;
    require security::various;
    security::level::set($o->{security});
    security::various::config_libsafe($::prefix, $o->{libsafe});
    security::various::config_security_user($::prefix, $o->{security_user});
}

sub write_fstab {
    my ($o) = @_;
    fs::write_fstab($o->{all_hds}, $::prefix) 
	if !$o->{isUpgrade} || $o->{isUpgrade} =~ /redhat|conectiva/ || $o->{migrate_device_names};
}

sub move_compressed_image_to_disk {
    my ($o) = @_;

    our $compressed_image_on_disk;
    return if $compressed_image_on_disk || $::local_install;

    my $name = 'mdkinst.sqfs';
    my ($loop, $current_image) = devices::find_compressed_image($name) or return;
    my $compressed_image_size = (-s $current_image) / 1024; #- put in KiB

    my $dir;
    if (availableRamMB() > 400) {
	$dir = '/tmp'; #- on tmpfs
    } else {
	my $tmp = fs::get::mntpoint2part('/tmp', $o->{fstab});
	if ($tmp && fs::df($tmp, $::prefix) / 2 > $compressed_image_size * 1.2) { #- we want at least 20% free afterwards
	    $dir = "$::prefix/tmp";
	} else {
	    my $root = fs::get::mntpoint2part('/', $o->{fstab});
	    my $root_free_MB = fs::df($root, $::prefix) / 2 / 1024;
	    my $wanted_size_MB = $o->{isUpgrade} || fs::get::mntpoint2part('/usr', $o->{fstab}) ? 150 : 300;
	    log::l("compressed image: root free $root_free_MB MB, wanted at least $wanted_size_MB MB");
	    if ($root_free_MB > $wanted_size_MB) {
		$dir = $tmp ? $::prefix : "$::prefix/tmp";
	    } else {
		$dir = '/tmp'; #- on tmpfs
		if (availableRamMB() < 200) {
		    log::l("ERROR: not much ram (" . availableRamMB() . " MB), we're going in the wall!");
		}
	    }
	}
    }
    $compressed_image_on_disk = "$dir/$name";

    if ($current_image ne $compressed_image_on_disk) {
	log::l("move_compressed_image_to_disk: copying $current_image to $compressed_image_on_disk");
	cp_af($current_image, $compressed_image_on_disk);
	run_program::run('losetup', '-r', $loop, $compressed_image_on_disk);
	unlink $current_image if $current_image eq "/tmp/$name";
    }
}

sub deploy_server_notify {
    my ($o) = @_;
    my $fallback_intf = "eth0";
    my $fallback_port = 3710;

    my ($server, $port) = $o->{deploy_server} =~ /^(.*?)(?::(\d+))?$/;
    if ($server) {
        require network::tools;
        require IO::Socket;
        $port ||= $fallback_port;
        my $intf = network::tools::get_current_gateway_interface() || $fallback_intf;
        my $mac = c::get_hw_address($intf);
        my $sock = IO::Socket::INET->new(PeerAddr => $server, PeerPort => $port, Proto => 'tcp');
        if ($sock) {
            print $sock "$mac\n";
            close($sock);
            log::l(qq(successfully notified deploy server $server on port $port));
        } else {
            log::l(qq(unable to contact deploy server $server on port $port));
        }
    } else {
        log::l(qq(unable to parse deploy server in string $o->{deploy_server}));
    }
}

#-###############################################################################
#- pcmcia various
#-###############################################################################
sub configure_pcmcia {
    my ($o) = @_;
    my $controller = detect_devices::pcmcia_controller_probe();
    $o->{pcmcia} ||= $controller && $controller->{driver} or return;
    log::l("configuring PCMCIA controller ($o->{pcmcia})");
    symlink "/tmp/stage2/$_", $_ foreach "/etc/pcmcia";
    eval { modules::load($o->{pcmcia}, 'pcmcia') };
    run_program::run("pcmcia-socket-startup");
}

1;
0</a>
<a id='n1201' href='#n1201'>1201</a>
<a id='n1202' href='#n1202'>1202</a>
<a id='n1203' href='#n1203'>1203</a>
<a id='n1204' href='#n1204'>1204</a>
<a id='n1205' href='#n1205'>1205</a>
<a id='n1206' href='#n1206'>1206</a>
<a id='n1207' href='#n1207'>1207</a>
<a id='n1208' href='#n1208'>1208</a>
<a id='n1209' href='#n1209'>1209</a>
<a id='n1210' href='#n1210'>1210</a>
<a id='n1211' href='#n1211'>1211</a>
<a id='n1212' href='#n1212'>1212</a>
<a id='n1213' href='#n1213'>1213</a>
<a id='n1214' href='#n1214'>1214</a>
<a id='n1215' href='#n1215'>1215</a>
<a id='n1216' href='#n1216'>1216</a>
<a id='n1217' href='#n1217'>1217</a>
<a id='n1218' href='#n1218'>1218</a>
<a id='n1219' href='#n1219'>1219</a>
<a id='n1220' href='#n1220'>1220</a>
<a id='n1221' href='#n1221'>1221</a>
<a id='n1222' href='#n1222'>1222</a>
<a id='n1223' href='#n1223'>1223</a>
<a id='n1224' href='#n1224'>1224</a>
<a id='n1225' href='#n1225'>1225</a>
<a id='n1226' href='#n1226'>1226</a>
<a id='n1227' href='#n1227'>1227</a>
<a id='n1228' href='#n1228'>1228</a>
<a id='n1229' href='#n1229'>1229</a>
<a id='n1230' href='#n1230'>1230</a>
<a id='n1231' href='#n1231'>1231</a>
<a id='n1232' href='#n1232'>1232</a>
<a id='n1233' href='#n1233'>1233</a>
<a id='n1234' href='#n1234'>1234</a>
<a id='n1235' href='#n1235'>1235</a>
<a id='n1236' href='#n1236'>1236</a>
<a id='n1237' href='#n1237'>1237</a>
<a id='n1238' href='#n1238'>1238</a>
<a id='n1239' href='#n1239'>1239</a>
<a id='n1240' href='#n1240'>1240</a>
<a id='n1241' href='#n1241'>1241</a>
<a id='n1242' href='#n1242'>1242</a>
<a id='n1243' href='#n1243'>1243</a>
<a id='n1244' href='#n1244'>1244</a>
<a id='n1245' href='#n1245'>1245</a>
<a id='n1246' href='#n1246'>1246</a>
<a id='n1247' href='#n1247'>1247</a>
<a id='n1248' href='#n1248'>1248</a>
<a id='n1249' href='#n1249'>1249</a>
<a id='n1250' href='#n1250'>1250</a>
<a id='n1251' href='#n1251'>1251</a>
<a id='n1252' href='#n1252'>1252</a>
<a id='n1253' href='#n1253'>1253</a>
<a id='n1254' href='#n1254'>1254</a>
<a id='n1255' href='#n1255'>1255</a>
<a id='n1256' href='#n1256'>1256</a>
<a id='n1257' href='#n1257'>1257</a>
<a id='n1258' href='#n1258'>1258</a>
<a id='n1259' href='#n1259'>1259</a>
<a id='n1260' href='#n1260'>1260</a>
<a id='n1261' href='#n1261'>1261</a>
<a id='n1262' href='#n1262'>1262</a>
<a id='n1263' href='#n1263'>1263</a>
<a id='n1264' href='#n1264'>1264</a>
<a id='n1265' href='#n1265'>1265</a>
<a id='n1266' href='#n1266'>1266</a>
<a id='n1267' href='#n1267'>1267</a>
<a id='n1268' href='#n1268'>1268</a>
<a id='n1269' href='#n1269'>1269</a>
<a id='n1270' href='#n1270'>1270</a>
<a id='n1271' href='#n1271'>1271</a>
<a id='n1272' href='#n1272'>1272</a>
<a id='n1273' href='#n1273'>1273</a>
<a id='n1274' href='#n1274'>1274</a>
<a id='n1275' href='#n1275'>1275</a>
<a id='n1276' href='#n1276'>1276</a>
<a id='n1277' href='#n1277'>1277</a>
<a id='n1278' href='#n1278'>1278</a>
<a id='n1279' href='#n1279'>1279</a>
<a id='n1280' href='#n1280'>1280</a>
<a id='n1281' href='#n1281'>1281</a>
<a id='n1282' href='#n1282'>1282</a>
</pre></td>
<td class='lines'><pre><code><span class="hl kwa">package</span> detect_devices<span class="hl opt">;</span> <span class="hl slc"># $Id$</span>

<span class="hl kwa">use</span> diagnostics<span class="hl opt">;</span>
<span class="hl kwa">use</span> strict<span class="hl opt">;</span>
<span class="hl kwa">use</span> vars <span class="hl str">qw(</span><span class="hl ipl">$pcitable_addons</span> <span class="hl str"></span><span class="hl ipl">$usbtable_addons</span><span class="hl str">)</span><span class="hl opt">;</span>

<span class="hl slc">#-######################################################################################</span>
<span class="hl slc">#- misc imports</span>
<span class="hl slc">#-######################################################################################</span>
<span class="hl kwa">use</span> <span class="hl kwc">log</span><span class="hl opt">;</span>
<span class="hl kwa">use</span> common<span class="hl opt">;</span>
<span class="hl kwa">use</span> devices<span class="hl opt">;</span>
<span class="hl kwa">use</span> run_program<span class="hl opt">;</span>
<span class="hl kwa">use</span> modules<span class="hl opt">;</span>
<span class="hl kwa">use</span> c<span class="hl opt">;</span>
<span class="hl kwa">use</span> feature <span class="hl str">&apos;state&apos;</span><span class="hl opt">;</span>

<span class="hl slc">#-#####################################################################################</span>
<span class="hl slc">#- Globals</span>
<span class="hl slc">#-#####################################################################################</span>
<span class="hl kwc">my</span> <span class="hl kwb">%serialprobe</span><span class="hl opt">;</span>

<span class="hl slc">#-######################################################################################</span>
<span class="hl slc">#- Functions</span>
<span class="hl slc">#-######################################################################################</span>

<span class="hl kwa">sub</span> get<span class="hl opt">() {</span>
    <span class="hl slc">#- Detect the default BIOS boot harddrive is kind of tricky. We may have IDE,</span>
    <span class="hl slc">#- SCSI and RAID devices on the same machine. From what I see so far, the default</span>
    <span class="hl slc">#- BIOS boot harddrive will be</span>
    <span class="hl slc">#- 1. The first IDE device if IDE exists. Or</span>
    <span class="hl slc">#- 2. The first SCSI device if SCSI exists. Or</span>
    <span class="hl slc">#- 3. The first RAID device if RAID exists.</span>

    getIDE<span class="hl opt">(),</span> getSCSI<span class="hl opt">(),</span> getVirtIO<span class="hl opt">(),</span> getDAC960<span class="hl opt">(),</span> getCompaqSmartArray<span class="hl opt">(),</span> getATARAID<span class="hl opt">();</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> hds<span class="hl opt">()         {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> may_be_a_hd<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">) }</span> get<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> tapes<span class="hl opt">()       {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;tape&apos;</span> <span class="hl opt">}</span> get<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> cdroms<span class="hl opt">()      {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;cdrom&apos;</span> <span class="hl opt">}</span> get<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> burners<span class="hl opt">()     {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> isBurner<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">) }</span> cdroms<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> dvdroms<span class="hl opt">()     {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> isDvdDrive<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">) }</span> cdroms<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> raw_zips<span class="hl opt">()    {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> member<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">},</span> <span class="hl str">&apos;fd&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;hd&apos;</span><span class="hl opt">) &amp;&amp;</span> isZipDrive<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">) }</span> get<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> ls120s<span class="hl opt">()      {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> member<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">},</span> <span class="hl str">&apos;fd&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;hd&apos;</span><span class="hl opt">) &amp;&amp;</span> isLS120Drive<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">) }</span> get<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> zips<span class="hl opt">()        {</span>
    <span class="hl kwc">map</span> <span class="hl opt">{</span> 
	<span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">} .=</span> <span class="hl num">4</span><span class="hl opt">;</span> 
	<span class="hl kwb">$_</span><span class="hl opt">;</span>
    <span class="hl opt">}</span> raw_zips<span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> floppies <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$o_not_detect_legacy_floppies</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwa">require</span> modules<span class="hl opt">;</span>
    <span class="hl kwc">state</span> <span class="hl kwb">&#64;fds</span><span class="hl opt">;</span>
    <span class="hl kwc">state</span> <span class="hl kwb">$legacy_already_detected</span><span class="hl opt">;</span>
    <span class="hl kwa">if</span> <span class="hl opt">(!</span><span class="hl kwb">$o_not_detect_legacy_floppies</span> <span class="hl opt">&amp;&amp; !</span><span class="hl kwb">$legacy_already_detected</span><span class="hl opt">) {</span>
        <span class="hl kwb">$legacy_already_detected</span> <span class="hl opt">=</span> <span class="hl num">1</span><span class="hl opt">;</span>
        <span class="hl kwc">eval</span> <span class="hl opt">{</span> modules<span class="hl opt">::</span>load<span class="hl opt">(</span><span class="hl str">&quot;floppy&quot;</span><span class="hl opt">)</span> <span class="hl kwa">if</span> <span class="hl opt">$::</span>isInstall <span class="hl opt">};</span>
        <span class="hl slc">#- do not bother probing /dev/fd0 and loading floppy device uselessly,</span>
        <span class="hl slc">#- it takes time and it is already done by boot process (if not in install):</span>
        <span class="hl slc">#-   /dev/fd0 is created by start_udev (/etc/udev/devices.d/default.nodes)</span>
        <span class="hl slc">#-   then hal probes /dev/fd0 and triggers floppy module loading through kernel&apos;s kmod</span>
        <span class="hl kwa">if</span> <span class="hl opt">(</span>any <span class="hl opt">{ (</span><span class="hl kwc">split</span><span class="hl opt">)[</span><span class="hl num">1</span><span class="hl opt">]</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;fd&apos;</span> <span class="hl opt">}</span> cat_<span class="hl opt">(</span><span class="hl str">&quot;/proc/devices&quot;</span><span class="hl opt">)) {</span>
            <span class="hl kwb">&#64;fds</span> <span class="hl opt">=</span> <span class="hl kwc">map</span> <span class="hl opt">{</span>
                <span class="hl kwc">my</span> <span class="hl kwb">$info</span> <span class="hl opt">=</span> c<span class="hl opt">::</span>floppy_info<span class="hl opt">(</span>devices<span class="hl opt">::</span>make<span class="hl opt">(</span><span class="hl str">&quot;fd</span><span class="hl ipl">$_</span><span class="hl str">&quot;</span><span class="hl opt">));</span>
                if_<span class="hl opt">(</span><span class="hl kwb">$info</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$info</span> <span class="hl kwc">ne</span> <span class="hl str">&apos;(null)&apos;</span><span class="hl opt">, {</span> device <span class="hl opt">=&gt;</span> <span class="hl str">&quot;fd</span><span class="hl ipl">$_</span><span class="hl str">&quot;</span><span class="hl opt">,</span> media_type <span class="hl opt">=&gt;</span> <span class="hl str">&apos;fd&apos;</span><span class="hl opt">,</span> info <span class="hl opt">=&gt;</span> <span class="hl kwb">$info</span> <span class="hl opt">});</span>
            <span class="hl opt">}</span> <span class="hl str">qw(0 1)</span><span class="hl opt">;</span>
        <span class="hl opt">}</span>
    <span class="hl opt">}</span>
        
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;ide</span> <span class="hl opt">=</span> ls120s<span class="hl opt">()</span> <span class="hl kwc">and eval</span> <span class="hl opt">{</span> modules<span class="hl opt">::</span>load<span class="hl opt">(</span><span class="hl str">&quot;ide_floppy&quot;</span><span class="hl opt">) };</span>

    <span class="hl kwc">eval</span> <span class="hl opt">{</span> modules<span class="hl opt">::</span>load<span class="hl opt">(</span><span class="hl str">&quot;usb_storage&quot;</span><span class="hl opt">) }</span> <span class="hl kwa">if</span> <span class="hl opt">$::</span>isInstall <span class="hl opt">&amp;&amp;</span> usbStorage<span class="hl opt">();</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;scsi</span> <span class="hl opt">=</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;fd&apos;</span> <span class="hl opt">}</span> getSCSI<span class="hl opt">();</span>
    <span class="hl kwb">&#64;ide, &#64;scsi, &#64;fds</span><span class="hl opt">;</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> floppies_dev<span class="hl opt">() {</span> <span class="hl kwc">map</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">} }</span> floppies<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> floppy<span class="hl opt">() {</span> first<span class="hl opt">(</span>floppies_dev<span class="hl opt">()) }</span>
<span class="hl slc">#- example ls120, model = &quot;LS-120 SLIM 02 UHD Floppy&quot;</span>

<span class="hl kwa">sub</span> removables<span class="hl opt">() {</span>
    floppies<span class="hl opt">(),</span> cdroms<span class="hl opt">(),</span> zips<span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_sys_cdrom_info <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">&#64;drives</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>

    <span class="hl kwc">my</span> <span class="hl kwb">&#64;drives_order</span><span class="hl opt">;</span>
    <span class="hl kwa">foreach</span> <span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&quot;/proc/sys/dev/cdrom/info&quot;</span><span class="hl opt">)) {</span>
	<span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$t, $l</span><span class="hl opt">) =</span> <span class="hl kwc">split</span> <span class="hl str">&apos;:&apos;</span><span class="hl opt">;</span>
	<span class="hl kwc">my</span> <span class="hl kwb">&#64;l</span><span class="hl opt">;</span>
	<span class="hl kwb">&#64;l</span> <span class="hl opt">=</span> <span class="hl kwc">split</span><span class="hl opt">(</span><span class="hl str">&apos; &apos;</span><span class="hl opt">,</span> <span class="hl kwb">$l</span><span class="hl opt">)</span> <span class="hl kwa">if</span> <span class="hl kwb">$l</span><span class="hl opt">;</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$t</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;drive name&apos;</span><span class="hl opt">) {</span>
	    <span class="hl kwb">&#64;drives_order</span> <span class="hl opt">=</span> <span class="hl kwc">map</span> <span class="hl opt">{</span>
		<span class="hl kwc">my</span> <span class="hl kwb">$dev</span> <span class="hl opt">=</span> <span class="hl kwb">$_</span><span class="hl opt">;</span>
		find <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl kwb">$dev</span> <span class="hl opt">}</span> <span class="hl kwb">&#64;drives</span><span class="hl opt">;</span>
	    <span class="hl opt">}</span> <span class="hl kwb">&#64;l</span><span class="hl opt">;</span>
	<span class="hl opt">}</span> <span class="hl kwa">else</span> <span class="hl opt">{</span>
	    <span class="hl kwc">my</span> <span class="hl kwb">$capacity</span><span class="hl opt">;</span>
	    <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$t</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;Can write CD-R&apos;</span><span class="hl opt">) {</span>
		<span class="hl kwb">$capacity</span> <span class="hl opt">=</span> <span class="hl str">&apos;burner&apos;</span><span class="hl opt">;</span>
	    <span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwb">$t</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;Can read DVD&apos;</span><span class="hl opt">) {</span>
		<span class="hl kwb">$capacity</span> <span class="hl opt">=</span> <span class="hl str">&apos;DVD&apos;</span><span class="hl opt">;</span>
	    <span class="hl opt">}</span>
	    <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$capacity</span><span class="hl opt">) {</span>
		each_index <span class="hl opt">{</span>
		    <span class="hl opt">(</span><span class="hl kwb">$drives_order</span><span class="hl opt">[$::</span>i<span class="hl opt">] || {})-&gt;{</span>capacity<span class="hl opt">} .=</span> <span class="hl str">&quot;</span><span class="hl ipl">$capacity</span> <span class="hl str">&quot;</span> <span class="hl kwa">if</span> <span class="hl kwb">$_</span><span class="hl opt">;</span>
		<span class="hl opt">}</span> <span class="hl kwb">&#64;l</span><span class="hl opt">;</span>
	    <span class="hl opt">}</span>
	<span class="hl opt">}</span>
    <span class="hl opt">}</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> complete_usb_storage_info <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">&#64;l</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>

    <span class="hl kwc">my</span> <span class="hl kwb">&#64;usb</span> <span class="hl opt">=</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwc">exists</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>usb_vendor<span class="hl opt">} }</span> <span class="hl kwb">&#64;l</span><span class="hl opt">;</span>

    <span class="hl kwa">foreach</span> <span class="hl kwc">my</span> <span class="hl kwb">$usb</span> <span class="hl opt">(</span>usb_probe<span class="hl opt">()) {</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwc">my</span> <span class="hl kwb">$e</span> <span class="hl opt">=</span> find <span class="hl opt">{ !</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>found<span class="hl opt">} &amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>usb_vendor<span class="hl opt">} ==</span> <span class="hl kwb">$usb</span><span class="hl opt">-&gt;{</span>vendor<span class="hl opt">} &amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>usb_id<span class="hl opt">} ==</span> <span class="hl kwb">$usb</span><span class="hl opt">-&gt;{</span>id<span class="hl opt">} }</span> <span class="hl kwb">&#64;usb</span><span class="hl opt">) {</span>
         <span class="hl kwc">my</span> <span class="hl kwb">$host</span> <span class="hl opt">=</span> get_sysfs_usbpath_for_block<span class="hl opt">(</span><span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">});</span>
         <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$host</span><span class="hl opt">) {</span>
             <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>info<span class="hl opt">} =</span> chomp_<span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&quot;/sys/block/</span><span class="hl ipl">$e</span><span class="hl str">-&gt;{device}/</span><span class="hl ipl">$host/</span><span class="hl str">../serial&quot;</span><span class="hl opt">));</span>
             <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>usb_description<span class="hl opt">} =</span> <span class="hl kwc">join</span><span class="hl opt">(</span><span class="hl str">&apos;|&apos;</span><span class="hl opt">,</span> 
                                          chomp_<span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&quot;/sys/block/</span><span class="hl ipl">$e</span><span class="hl str">-&gt;{device}/</span><span class="hl ipl">$host/</span><span class="hl str">../manufacturer&quot;</span><span class="hl opt">)),</span>
                                          chomp_<span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&quot;/sys/block/</span><span class="hl ipl">$e</span><span class="hl str">-&gt;{device}/</span><span class="hl ipl">$host/</span><span class="hl str">../product&quot;</span><span class="hl opt">)));</span>
         <span class="hl opt">}</span>
         <span class="hl kwc">local</span> <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>found<span class="hl opt">} =</span> <span class="hl num">1</span><span class="hl opt">;</span>
	    <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span><span class="hl str">&quot;usb_</span><span class="hl ipl">$_</span><span class="hl str">&quot;</span><span class="hl opt">} ||=</span> <span class="hl kwb">$usb</span><span class="hl opt">-&gt;{</span><span class="hl kwb">$_</span><span class="hl opt">}</span> <span class="hl kwa">foreach</span> <span class="hl kwc">keys</span> <span class="hl kwb">%$usb</span><span class="hl opt">;</span>
	<span class="hl opt">}</span>
    <span class="hl opt">}</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> isBurner <span class="hl opt">{</span> 
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$e</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>capacity<span class="hl opt">} =~</span> <span class="hl kwd">/burner/</span> <span class="hl kwc">and</span> <span class="hl kwa">return</span> <span class="hl num">1</span><span class="hl opt">;</span>
      
    <span class="hl slc">#- do not work for SCSI</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$f</span> <span class="hl opt">=</span> tryOpen<span class="hl opt">(</span><span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">});</span> <span class="hl slc">#- SCSI burner are not detected this way.</span>
    <span class="hl kwb">$f</span> <span class="hl opt">&amp;&amp;</span> c<span class="hl opt">::</span>isBurner<span class="hl opt">(</span><span class="hl kwc">fileno</span><span class="hl opt">(</span><span class="hl kwb">$f</span><span class="hl opt">));</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> isDvdDrive <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$e</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>capacity<span class="hl opt">} =~</span> <span class="hl kwd">/DVD/</span> <span class="hl opt">||</span> <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>info<span class="hl opt">} =~</span> <span class="hl kwd">/DVD/</span> <span class="hl kwc">and</span> <span class="hl kwa">return</span> <span class="hl num">1</span><span class="hl opt">;</span>

    <span class="hl slc">#- do not work for SCSI</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$f</span> <span class="hl opt">=</span> tryOpen<span class="hl opt">(</span><span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">});</span>
    <span class="hl kwb">$f</span> <span class="hl opt">&amp;&amp;</span> c<span class="hl opt">::</span>isDvdDrive<span class="hl opt">(</span><span class="hl kwc">fileno</span><span class="hl opt">(</span><span class="hl kwb">$f</span><span class="hl opt">));</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> isZipDrive <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]{</span>info<span class="hl opt">} =~</span> <span class="hl kwd">/ZIP\s+\d+/</span> <span class="hl opt">}</span> <span class="hl slc">#- accept ZIP 100, untested for bigger ZIP drive.</span>
<span class="hl kwa">sub</span> isLS120Drive <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]{</span>info<span class="hl opt">} =~</span> <span class="hl kwd">/LS-?120|144MB/</span> <span class="hl opt">}</span>
<span class="hl kwa">sub</span> isKeyUsb <span class="hl opt">{</span> begins_with<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]{</span>usb_media_type<span class="hl opt">} ||</span> <span class="hl str">&apos;&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;Mass Storage&apos;</span><span class="hl opt">) &amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]{</span>media_type<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;hd&apos;</span> <span class="hl opt">}</span>
<span class="hl kwa">sub</span> isFloppyUsb <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]{</span>usb_driver<span class="hl opt">} &amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]{</span>usb_driver<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;Removable:floppy&apos;</span> <span class="hl opt">}</span>
<span class="hl kwa">sub</span> may_be_a_hd <span class="hl opt">{</span> 
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$e</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;hd&apos;</span> <span class="hl opt">&amp;&amp; !(</span>
	isZipDrive<span class="hl opt">(</span><span class="hl kwb">$e</span><span class="hl opt">)</span> 
           <span class="hl opt">||</span> isLS120Drive<span class="hl opt">(</span><span class="hl kwb">$e</span><span class="hl opt">)</span>
           <span class="hl opt">||</span> begins_with<span class="hl opt">(</span><span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>usb_media_type<span class="hl opt">} ||</span> <span class="hl str">&apos;&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;Mass Storage|Floppy (UFI)&apos;</span><span class="hl opt">)</span>
    <span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_sysfs_field_from_link <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$device, $field</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$l</span> <span class="hl opt">=</span> <span class="hl kwc">readlink</span><span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$device/$field</span><span class="hl str">&quot;</span><span class="hl opt">);</span>
    <span class="hl kwb">$l</span> <span class="hl opt">=~</span> <span class="hl kwd">s!.*/!!</span><span class="hl opt">;</span>
    <span class="hl kwb">$l</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_sysfs_usbpath_for_block <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$device</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$host</span> <span class="hl opt">=</span> <span class="hl kwc">readlink</span><span class="hl opt">(</span><span class="hl str">&quot;/sys/block/</span><span class="hl ipl">$device/device</span><span class="hl str">&quot;</span><span class="hl opt">);</span>
    <span class="hl kwb">$host</span> <span class="hl opt">=~</span> <span class="hl kwd">s!/host.*!!</span><span class="hl opt">;</span>
    <span class="hl kwb">$host</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_scsi_driver <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">&#64;l</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl slc"># find driver of host controller from sysfs:</span>
    <span class="hl kwa">foreach</span> <span class="hl opt">(</span><span class="hl kwb">&#64;l</span><span class="hl opt">) {</span>
	<span class="hl kwa">next if</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">};</span>
	<span class="hl kwc">my</span> <span class="hl kwb">$host</span> <span class="hl opt">=</span> get_sysfs_usbpath_for_block<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">});</span>
	<span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =</span> get_sysfs_field_from_link<span class="hl opt">(</span><span class="hl str">&quot;/sys/block/</span><span class="hl ipl">$_</span><span class="hl str">-&gt;{device}/</span><span class="hl ipl">$host</span><span class="hl str">&quot;</span><span class="hl opt">,</span> <span class="hl str">&apos;driver&apos;</span><span class="hl opt">);</span>
    <span class="hl opt">}</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> getSCSI<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$dev_dir</span> <span class="hl opt">=</span> <span class="hl str">&apos;/sys/bus/scsi/devices&apos;</span><span class="hl opt">;</span>

    <span class="hl kwc">my</span> <span class="hl kwb">&#64;scsi_types</span> <span class="hl opt">= (</span>
	<span class="hl str">&quot;Direct-Access&quot;</span><span class="hl opt">,</span>
	<span class="hl str">&quot;Sequential-Access&quot;</span><span class="hl opt">,</span>
	<span class="hl str">&quot;Printer&quot;</span><span class="hl opt">,</span>
	<span class="hl str">&quot;Processor&quot;</span><span class="hl opt">,</span>
	<span class="hl str">&quot;WORM&quot;</span><span class="hl opt">,</span>
	<span class="hl str">&quot;CD-ROM&quot;</span><span class="hl opt">,</span>
	<span class="hl str">&quot;Scanner&quot;</span><span class="hl opt">,</span>
	<span class="hl str">&quot;Optical Device&quot;</span><span class="hl opt">,</span>
	<span class="hl str">&quot;Medium Changer&quot;</span><span class="hl opt">,</span>
	<span class="hl str">&quot;Communications&quot;</span><span class="hl opt">,</span>
    <span class="hl opt">);</span>

    <span class="hl kwc">my</span> <span class="hl kwb">&#64;l</span><span class="hl opt">;</span>
    <span class="hl kwa">foreach</span> <span class="hl opt">(</span>all<span class="hl opt">(</span><span class="hl kwb">$dev_dir</span><span class="hl opt">)) {</span>
	<span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$host, $channel, $id, $lun</span><span class="hl opt">) =</span> <span class="hl kwc">split</span> <span class="hl str">&apos;:&apos;</span><span class="hl opt">;</span>
	<span class="hl kwc">defined</span> <span class="hl kwb">$lun</span> <span class="hl kwc">or</span> <span class="hl kwa">next</span><span class="hl opt">;</span>

	<span class="hl kwc">my</span> <span class="hl kwb">$dir</span> <span class="hl opt">=</span> <span class="hl str">&quot;</span><span class="hl ipl">$dev_dir/$_</span><span class="hl str">&quot;</span><span class="hl opt">;</span>

	<span class="hl slc"># handle both old and new kernels:</span>
	<span class="hl kwc">my</span> <span class="hl kwb">$node</span> <span class="hl opt">=</span>  find <span class="hl opt">{ -</span>e <span class="hl kwb">$_</span> <span class="hl opt">}</span> <span class="hl str">&quot;</span><span class="hl ipl">$dir/block</span><span class="hl str">&quot;</span><span class="hl opt">,</span> top<span class="hl opt">(</span>glob_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$dir/block*</span><span class="hl str">&quot;</span><span class="hl opt">)),</span> <span class="hl str">&quot;</span><span class="hl ipl">$dir/tape</span><span class="hl str">&quot;</span><span class="hl opt">,</span> top<span class="hl opt">(</span>glob_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$dir/scsi_generic*</span><span class="hl str">&quot;</span><span class="hl opt">));</span>
	<span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$device</span><span class="hl opt">) =</span> <span class="hl kwc">readlink</span><span class="hl opt">(</span><span class="hl kwb">$node</span><span class="hl opt">) =~</span> <span class="hl kwd">m!/(?:scsi_(?:generic|tape)|block)/(.*)!</span><span class="hl opt">;</span>
        <span class="hl kwa">if</span> <span class="hl opt">(!</span><span class="hl kwb">$device</span><span class="hl opt">) {</span>
            <span class="hl opt">(</span><span class="hl kwb">$device</span><span class="hl opt">) =</span> top<span class="hl opt">(</span>glob_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$node/*</span><span class="hl str">&quot;</span><span class="hl opt">)) =~</span> m<span class="hl opt">!/(</span>?<span class="hl opt">:</span>scsi_<span class="hl opt">(</span>?<span class="hl opt">:</span>generic<span class="hl opt">|</span>tape<span class="hl opt">)|</span>block<span class="hl opt">)/(.*)!;</span>
        <span class="hl opt">}</span>
	<span class="hl kwc">warn</span><span class="hl opt">(</span><span class="hl str">&quot;cannot get info for device (</span><span class="hl ipl">$_</span><span class="hl str">)&quot;</span><span class="hl opt">),</span> <span class="hl kwa">next if</span> <span class="hl opt">!</span><span class="hl kwb">$device</span><span class="hl opt">;</span>

	<span class="hl kwc">my</span> <span class="hl kwb">$usb_dir</span> <span class="hl opt">=</span> <span class="hl kwc">readlink</span><span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$node/device</span><span class="hl str">&quot;</span><span class="hl opt">) =~</span> m<span class="hl opt">!/</span>usb<span class="hl opt">! &amp;&amp;</span> <span class="hl str">&quot;</span><span class="hl ipl">$node/device/</span><span class="hl str">../../../..&quot;</span><span class="hl opt">;</span>
	<span class="hl kwc">my</span> <span class="hl kwb">$get_usb</span> <span class="hl opt">=</span> <span class="hl kwa">sub</span> <span class="hl opt">{</span> chomp_<span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$usb_dir/$_</span><span class="hl str">[0]&quot;</span><span class="hl opt">)) };</span>

	<span class="hl kwc">my</span> <span class="hl kwb">$get</span> <span class="hl opt">=</span> <span class="hl kwa">sub</span> <span class="hl opt">{</span>
	    <span class="hl kwc">my</span> <span class="hl kwb">$s</span> <span class="hl opt">=</span> cat_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$dir/$_</span><span class="hl str">[0]&quot;</span><span class="hl opt">);</span>
	    <span class="hl kwb">$s</span> <span class="hl opt">=~</span> <span class="hl kwd">s/\s+$//</span><span class="hl opt">;</span>
	    <span class="hl kwb">$s</span><span class="hl opt">;</span>
	<span class="hl opt">};</span>

	<span class="hl slc"># Old hp scanners report themselves as &quot;Processor&quot;s</span>
	<span class="hl slc"># (see linux/include/scsi/scsi.h and sans-find-scanner.1)</span>
	<span class="hl kwc">my</span> <span class="hl kwb">$raw_type</span> <span class="hl opt">=</span> <span class="hl kwb">$scsi_types</span><span class="hl opt">[</span><span class="hl kwb">$get</span><span class="hl opt">-&gt;(</span><span class="hl str">&apos;type&apos;</span><span class="hl opt">)];</span>

	<span class="hl kwc">my</span> <span class="hl kwb">$media_type</span> <span class="hl opt">= ${{</span> st <span class="hl opt">=&gt;</span> <span class="hl str">&apos;tape&apos;</span><span class="hl opt">,</span> sr <span class="hl opt">=&gt;</span> <span class="hl str">&apos;cdrom&apos;</span><span class="hl opt">,</span> sd <span class="hl opt">=&gt;</span> <span class="hl str">&apos;hd&apos;</span><span class="hl opt">,</span> sg <span class="hl opt">=&gt;</span> <span class="hl str">&apos;generic&apos;</span> <span class="hl opt">}}{</span><span class="hl kwc">substr</span><span class="hl opt">(</span><span class="hl kwb">$device,</span> <span class="hl num">0</span><span class="hl opt">,</span> <span class="hl num">2</span><span class="hl opt">)} ||</span>
	  <span class="hl kwb">$raw_type</span> <span class="hl opt">=~</span> <span class="hl kwd">/Scanner|Processor/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl str">&apos;scanner&apos;</span><span class="hl opt">;</span>

	<span class="hl kwc">push</span> <span class="hl kwb">&#64;l,</span> <span class="hl opt">{</span> info <span class="hl opt">=&gt;</span>  <span class="hl kwb">$get</span><span class="hl opt">-&gt;(</span><span class="hl str">&apos;vendor&apos;</span><span class="hl opt">) .</span> <span class="hl str">&apos; &apos;</span> <span class="hl opt">.</span> <span class="hl kwb">$get</span><span class="hl opt">-&gt;(</span><span class="hl str">&apos;model&apos;</span><span class="hl opt">),</span> host <span class="hl opt">=&gt;</span> <span class="hl kwb">$host,</span> channel <span class="hl opt">=&gt;</span> <span class="hl kwb">$channel,</span> id <span class="hl opt">=&gt;</span> <span class="hl kwb">$id,</span> lun <span class="hl opt">=&gt;</span> <span class="hl kwb">$lun,</span> 
	  description <span class="hl opt">=&gt;</span> <span class="hl kwc">join</span><span class="hl opt">(</span><span class="hl str">&apos;|&apos;</span><span class="hl opt">,</span> <span class="hl kwb">$get</span><span class="hl opt">-&gt;(</span><span class="hl str">&apos;vendor&apos;</span><span class="hl opt">),</span> <span class="hl kwb">$get</span><span class="hl opt">-&gt;(</span><span class="hl str">&apos;model&apos;</span><span class="hl opt">)),</span>
	  bus <span class="hl opt">=&gt;</span> <span class="hl str">&apos;SCSI&apos;</span><span class="hl opt">,</span> media_type <span class="hl opt">=&gt;</span> <span class="hl kwb">$media_type,</span> device <span class="hl opt">=&gt;</span> <span class="hl kwb">$device,</span>
	    <span class="hl kwb">$usb_dir</span> ? <span class="hl opt">(</span>
	  usb_vendor <span class="hl opt">=&gt;</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$get_usb</span><span class="hl opt">-&gt;(</span><span class="hl str">&apos;idVendor&apos;</span><span class="hl opt">)),</span> usb_id <span class="hl opt">=&gt;</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$get_usb</span><span class="hl opt">-&gt;(</span><span class="hl str">&apos;idProduct&apos;</span><span class="hl opt">)),</span>
	    <span class="hl opt">) : (),</span>
        <span class="hl opt">};</span>
    <span class="hl opt">}</span> 

    <span class="hl kwb">&#64;l</span> <span class="hl opt">=</span> <span class="hl kwc">sort</span> <span class="hl opt">{</span> <span class="hl kwb">$a</span><span class="hl opt">-&gt;{</span>host<span class="hl opt">} &lt;=&gt;</span> <span class="hl kwb">$b</span><span class="hl opt">-&gt;{</span>host<span class="hl opt">} ||</span> <span class="hl kwb">$a</span><span class="hl opt">-&gt;{</span>channel<span class="hl opt">} &lt;=&gt;</span> <span class="hl kwb">$b</span><span class="hl opt">-&gt;{</span>channel<span class="hl opt">} ||</span> <span class="hl kwb">$a</span><span class="hl opt">-&gt;{</span>id<span class="hl opt">} &lt;=&gt;</span> <span class="hl kwb">$b</span><span class="hl opt">-&gt;{</span>id<span class="hl opt">} ||</span> <span class="hl kwb">$a</span><span class="hl opt">-&gt;{</span>lun<span class="hl opt">} &lt;=&gt;</span> <span class="hl kwb">$b</span><span class="hl opt">-&gt;{</span>lun<span class="hl opt">} }</span> <span class="hl kwb">&#64;l</span><span class="hl opt">;</span>

    complete_usb_storage_info<span class="hl opt">(</span><span class="hl kwb">&#64;l</span><span class="hl opt">);</span>

    <span class="hl kwa">foreach</span> <span class="hl opt">(</span><span class="hl kwb">&#64;l</span><span class="hl opt">) {</span>
	<span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">} =</span> <span class="hl str">&apos;fd&apos;</span> <span class="hl kwa">if</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;hd&apos;</span> <span class="hl opt">&amp;&amp;</span> isFloppyUsb<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">);</span>
    <span class="hl opt">}</span>

    get_sys_cdrom_info<span class="hl opt">(</span><span class="hl kwb">&#64;l</span><span class="hl opt">);</span>
    get_scsi_driver<span class="hl opt">(</span><span class="hl kwb">&#64;l</span><span class="hl opt">);</span>
    <span class="hl kwb">&#64;l</span><span class="hl opt">;</span>
<span class="hl opt">}</span>


<span class="hl kwc">my</span> <span class="hl kwb">%eide_hds</span> <span class="hl opt">= (</span>
    <span class="hl str">&quot;ASUS&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Asus&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;CD-ROM CDU&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Sony&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;CD-ROM Drive/F5D&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;ASUSTeK&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;Compaq&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Compaq&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;CONNER&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Conner Peripherals&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;IBM&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;IBM&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;FUJITSU&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Fujitsu&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;HITACHI&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Hitachi&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;Lite-On&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Lite-On Technology Corp.&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;LITE-ON&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Lite-On Technology Corp.&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;LTN&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Lite-On Technology Corp.&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;IOMEGA&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Iomega&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;MAXTOR&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Maxtor&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;Maxtor&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Maxtor&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;Micropolis&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Micropolis&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;Pioneer&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Pioneer&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;PLEXTOR&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Plextor&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;QUANTUM&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Quantum&quot;</span><span class="hl opt">,</span> 
    <span class="hl str">&quot;SAMSUNG&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Samsung&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;Seagate &quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Seagate Technology&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;ST3&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Seagate Technology&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;TEAC&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Teac&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;TOSHIBA&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Toshiba&quot;</span><span class="hl opt">,</span>
    <span class="hl str">&quot;WDC&quot;</span> <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Western Digital Corp.&quot;</span><span class="hl opt">,</span>
<span class="hl opt">);</span>


<span class="hl kwa">sub</span> getIDE<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;idi</span><span class="hl opt">;</span>

    <span class="hl slc">#- what about a system with absolutely no IDE on it, like some sparc machine.</span>
    <span class="hl opt">-</span>e <span class="hl str">&quot;/proc/ide&quot;</span> <span class="hl kwc">or</span> <span class="hl kwa">return</span> <span class="hl opt">();</span>

    <span class="hl slc">#- Great. 2.2 kernel, things are much easier and less error prone.</span>
    <span class="hl kwa">foreach</span> <span class="hl kwc">my</span> <span class="hl kwb">$d</span> <span class="hl opt">(</span><span class="hl kwc">sort</span> <span class="hl opt">&#64;{[</span>glob_<span class="hl opt">(</span><span class="hl str">&apos;/proc/ide/hd*&apos;</span><span class="hl opt">)]}) {</span>
	cat_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$d/driver</span><span class="hl str">&quot;</span><span class="hl opt">) =~ /</span>ide-scsi<span class="hl kwd">/ and next; #- already appears in /p</span>roc<span class="hl kwd">/scsi/scsi</span>
	<span class="hl kwc">my</span> <span class="hl kwb">$t</span> <span class="hl opt">=</span> chomp_<span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$d/media</span><span class="hl str">&quot;</span><span class="hl opt">));</span>
	<span class="hl kwc">my</span> <span class="hl kwb">$type</span> <span class="hl opt">= ${{</span> disk <span class="hl opt">=&gt;</span> <span class="hl str">&apos;hd&apos;</span><span class="hl opt">,</span> cdrom <span class="hl opt">=&gt;</span> <span class="hl str">&apos;cdrom&apos;</span><span class="hl opt">,</span> tape <span class="hl opt">=&gt;</span> <span class="hl str">&apos;tape&apos;</span><span class="hl opt">,</span> floppy <span class="hl opt">=&gt;</span> <span class="hl str">&apos;fd&apos;</span> <span class="hl opt">}}{</span><span class="hl kwb">$t</span><span class="hl opt">}</span> <span class="hl kwc">or</span> <span class="hl kwa">next</span><span class="hl opt">;</span>
	<span class="hl kwc">my</span> <span class="hl kwb">$info</span> <span class="hl opt">=</span> chomp_<span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$d/model</span><span class="hl str">&quot;</span><span class="hl opt">)) ||</span> <span class="hl str">&quot;(none)&quot;</span><span class="hl opt">;</span>

	<span class="hl kwc">my</span> <span class="hl kwb">$num</span> <span class="hl opt">=</span> <span class="hl kwc">ord</span><span class="hl opt">((</span><span class="hl kwb">$d</span> <span class="hl opt">=~</span> <span class="hl kwd">/(.)$/</span><span class="hl opt">)[</span><span class="hl num">0</span><span class="hl opt">]) -</span> <span class="hl kwc">ord</span> <span class="hl str">&apos;a&apos;</span><span class="hl opt">;</span>
	<span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$vendor, $model</span><span class="hl opt">) =</span> <span class="hl kwc">map</span> <span class="hl opt">{</span> 
	    if_<span class="hl opt">(</span><span class="hl kwb">$info</span> <span class="hl opt">=~</span> <span class="hl kwd">/^$_(-|\s)*(.*)/</span><span class="hl opt">,</span> <span class="hl kwb">$eide_hds</span><span class="hl opt">{</span><span class="hl kwb">$_</span><span class="hl opt">},</span> <span class="hl kwb">$2</span><span class="hl opt">);</span>
	<span class="hl opt">}</span> <span class="hl kwc">keys</span> <span class="hl kwb">%eide_hds</span><span class="hl opt">;</span>

	<span class="hl kwc">my</span> <span class="hl kwb">$host</span> <span class="hl opt">=</span> <span class="hl kwb">$num</span><span class="hl opt">;</span>
	<span class="hl opt">(</span><span class="hl kwb">$host,</span> <span class="hl kwc">my</span> <span class="hl kwb">$id</span><span class="hl opt">) =</span> divide<span class="hl opt">(</span><span class="hl kwb">$host,</span> <span class="hl num">2</span><span class="hl opt">);</span>
	<span class="hl opt">(</span><span class="hl kwb">$host,</span> <span class="hl kwc">my</span> <span class="hl kwb">$channel</span><span class="hl opt">) =</span> divide<span class="hl opt">(</span><span class="hl kwb">$host,</span> <span class="hl num">2</span><span class="hl opt">);</span>

	<span class="hl kwc">push</span> <span class="hl kwb">&#64;idi,</span> <span class="hl opt">{</span> media_type <span class="hl opt">=&gt;</span> <span class="hl kwb">$type,</span> device <span class="hl opt">=&gt;</span> basename<span class="hl opt">(</span><span class="hl kwb">$d</span><span class="hl opt">),</span> 
		     info <span class="hl opt">=&gt;</span> <span class="hl kwb">$info,</span> host <span class="hl opt">=&gt;</span> <span class="hl kwb">$host,</span> channel <span class="hl opt">=&gt;</span> <span class="hl kwb">$channel,</span> id <span class="hl opt">=&gt;</span> <span class="hl kwb">$id,</span> bus <span class="hl opt">=&gt;</span> <span class="hl str">&apos;ide&apos;</span><span class="hl opt">,</span> 
		     if_<span class="hl opt">(</span><span class="hl kwb">$vendor,</span> Vendor <span class="hl opt">=&gt;</span> <span class="hl kwb">$vendor</span><span class="hl opt">),</span> if_<span class="hl opt">(</span><span class="hl kwb">$model,</span> Model <span class="hl opt">=&gt;</span> <span class="hl kwb">$model</span><span class="hl opt">) };</span>
    <span class="hl opt">}</span>
    get_sys_cdrom_info<span class="hl opt">(</span><span class="hl kwb">&#64;idi</span><span class="hl opt">);</span>
    <span class="hl kwb">&#64;idi</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> block_devices<span class="hl opt">() {</span>
    <span class="hl opt">-</span>d <span class="hl str">&apos;/sys/block&apos;</span> 
      ? <span class="hl kwc">map</span> <span class="hl opt">{</span> s<span class="hl opt">|!|</span><span class="hl kwd">/|; $_ } all(&apos;/s</span>ys<span class="hl opt">/</span>block<span class="hl str">&apos;) </span>
<span class="hl str">      : map {</span> <span class="hl ipl">$_</span><span class="hl str">-&gt;{dev} } do { require fs::proc_partitions; fs::proc_partitions::read_raw() };</span>
<span class="hl str">}</span>
<span class="hl str"></span>
<span class="hl str">sub getCompaqSmartArray() {</span>
<span class="hl str">    my (</span><span class="hl ipl">&#64;idi,</span> <span class="hl str"></span><span class="hl ipl">$f</span><span class="hl str">);</span>
<span class="hl str"></span>
<span class="hl str">    foreach (&apos;</span>array<span class="hl opt">/</span>ida<span class="hl str">&apos;, &apos;</span>cpqarray<span class="hl opt">/</span>ida<span class="hl str">&apos;, &apos;</span>cciss<span class="hl opt">/</span>cciss<span class="hl str">&apos;) {</span>
<span class="hl str">	my</span> <span class="hl ipl">$prefix</span> <span class="hl str">= &quot;/proc/driver/</span><span class="hl ipl">$_</span><span class="hl str">&quot;; #- kernel 2.4 places it here</span>
<span class="hl str"></span>	<span class="hl ipl">$prefix</span> <span class="hl str">= &quot;/proc/</span><span class="hl ipl">$_</span><span class="hl str">&quot; if !-e &quot;${prefix}0&quot;; #- kernel 2.2</span>
<span class="hl str"></span>
<span class="hl str">	my (</span><span class="hl ipl">$name</span><span class="hl str">) = m|/(.*)|;</span>
<span class="hl str">	for (my</span> <span class="hl ipl">$i</span> <span class="hl str">= 0; -r (</span><span class="hl ipl">$f</span> <span class="hl str">= &quot;${prefix}</span><span class="hl ipl">$i</span><span class="hl str">&quot;);</span> <span class="hl ipl">$i++</span><span class="hl str">) {</span>
<span class="hl str">	    my</span> <span class="hl ipl">&#64;raw_devices</span> <span class="hl str">= cat_(</span><span class="hl ipl">$f</span><span class="hl str">) =~ m|^\s*(</span><span class="hl ipl">$name/</span><span class="hl str">.*?):|gm;</span>
<span class="hl str"></span>
<span class="hl str">	    #- this is ugly and buggy. keeping it for 2007.0</span>
<span class="hl str">	    #- on a cciss, cciss/cciss0 didn&apos;</span>t contain c0d0<span class="hl opt">,</span> but cciss<span class="hl opt">/</span>cciss1 did contain c0d1
	    <span class="hl slc">#- the line below adds both c0d0 and c0d1 for cciss0, and so some duplicates</span>
	    <span class="hl kwb">&#64;raw_devices</span> <span class="hl kwc">or</span> <span class="hl kwb">&#64;raw_devices</span> <span class="hl opt">=</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwd">m!^$name/!</span> <span class="hl opt">}</span> block_devices<span class="hl opt">();</span>

	    <span class="hl kwa">foreach</span> <span class="hl kwc">my</span> <span class="hl kwb">$raw_device</span> <span class="hl opt">(</span><span class="hl kwb">&#64;raw_devices</span><span class="hl opt">) {</span>
		<span class="hl kwc">my</span> <span class="hl kwb">$device</span> <span class="hl opt">= -</span>d <span class="hl str">&quot;/dev/</span><span class="hl ipl">$raw_device</span><span class="hl str">&quot;</span> ? <span class="hl str">&quot;</span><span class="hl ipl">$raw_device/disc</span><span class="hl str">&quot;</span> <span class="hl opt">:</span> <span class="hl kwb">$raw_device</span><span class="hl opt">;</span>
		<span class="hl kwc">push</span> <span class="hl kwb">&#64;idi,</span> <span class="hl opt">{</span> device <span class="hl opt">=&gt;</span> <span class="hl kwb">$device,</span> prefix <span class="hl opt">=&gt;</span> <span class="hl kwb">$raw_device</span> <span class="hl opt">.</span> <span class="hl str">&apos;p&apos;</span><span class="hl opt">,</span> 
			     info <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Compaq RAID logical disk&quot;</span><span class="hl opt">,</span>
			     media_type <span class="hl opt">=&gt;</span> <span class="hl str">&apos;hd&apos;</span><span class="hl opt">,</span> bus <span class="hl opt">=&gt;</span> <span class="hl kwb">$name</span> <span class="hl opt">};</span>
	    <span class="hl opt">}</span>
	<span class="hl opt">}</span>
    <span class="hl opt">}</span>
    <span class="hl slc">#- workaround the buggy code above. this should be safe though</span>
    uniq_ <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">} }</span> <span class="hl kwb">&#64;idi</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> getDAC960<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">%idi</span><span class="hl opt">;</span>

    <span class="hl slc">#- We are looking for lines of this format:DAC960#0:</span>
    <span class="hl slc">#- /dev/rd/c0d0: RAID-7, Online, 17928192 blocks, Write Thru0123456790123456789012</span>
    <span class="hl kwa">foreach</span> <span class="hl opt">(</span>syslog<span class="hl opt">()) {</span>
	<span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$device, $info</span><span class="hl opt">) =</span> m<span class="hl opt">|</span><span class="hl kwd">/dev/</span><span class="hl opt">(</span>rd<span class="hl opt">/.*</span>?<span class="hl opt">): (.*</span>?<span class="hl opt">),|</span> <span class="hl kwc">or</span> <span class="hl kwa">next</span><span class="hl opt">;</span>
	<span class="hl kwb">$idi</span><span class="hl opt">{</span><span class="hl kwb">$device</span><span class="hl opt">} = {</span> info <span class="hl opt">=&gt;</span> <span class="hl kwb">$info,</span> media_type <span class="hl opt">=&gt;</span> <span class="hl str">&apos;hd&apos;</span><span class="hl opt">,</span> device <span class="hl opt">=&gt;</span> <span class="hl kwb">$device,</span> bus <span class="hl opt">=&gt;</span> <span class="hl str">&apos;dac960&apos;</span> <span class="hl opt">};</span>
    <span class="hl opt">}</span>
    <span class="hl kwc">values</span> <span class="hl kwb">%idi</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> getATARAID<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">%l</span><span class="hl opt">;</span>
    <span class="hl kwa">foreach</span> <span class="hl opt">(</span>syslog<span class="hl opt">()) {</span>
	<span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$device</span><span class="hl opt">) =</span> m<span class="hl opt">|^</span>\s<span class="hl opt">*(</span>ataraid<span class="hl opt">/</span>d\d<span class="hl opt">+):|</span> <span class="hl kwc">or</span> <span class="hl kwa">next</span><span class="hl opt">;</span>
	<span class="hl kwb">$l</span><span class="hl opt">{</span><span class="hl kwb">$device</span><span class="hl opt">} = {</span> info <span class="hl opt">=&gt;</span> <span class="hl str">&apos;ATARAID block device&apos;</span><span class="hl opt">,</span> media_type <span class="hl opt">=&gt;</span> <span class="hl str">&apos;hd&apos;</span><span class="hl opt">,</span> device <span class="hl opt">=&gt;</span> <span class="hl kwb">$device,</span> bus <span class="hl opt">=&gt;</span> <span class="hl str">&apos;ataraid&apos;</span> <span class="hl opt">};</span>
	<span class="hl kwc">log</span><span class="hl opt">::</span>l<span class="hl opt">(</span><span class="hl str">&quot;ATARAID:</span> <span class="hl ipl">$device</span><span class="hl str">&quot;</span><span class="hl opt">);</span>
    <span class="hl opt">}</span>
    <span class="hl kwc">values</span> <span class="hl kwb">%l</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> getVirtIO<span class="hl opt">() {</span>
    <span class="hl opt">-</span>d <span class="hl str">&apos;/sys/bus/virtio/devices&apos;</span> <span class="hl kwc">or</span> <span class="hl kwa">return</span><span class="hl opt">;</span>
    <span class="hl kwc">map</span> <span class="hl opt">{</span>
            <span class="hl opt">{</span> device <span class="hl opt">=&gt;</span> basename<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">),</span> info <span class="hl opt">=&gt;</span> <span class="hl str">&quot;VirtIO block device&quot;</span><span class="hl opt">,</span> media_type <span class="hl opt">=&gt;</span> <span class="hl str">&apos;hd&apos;</span><span class="hl opt">,</span> bus <span class="hl opt">=&gt;</span> <span class="hl str">&apos;virtio&apos;</span> <span class="hl opt">}</span>
    <span class="hl opt">}</span>
    <span class="hl kwc">glob</span><span class="hl opt">(</span><span class="hl str">&quot;/sys/bus/virtio/devices/*/block/*&quot;</span><span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl slc"># cpu_name : arch() =~ /^alpha/ ? &quot;cpu	&quot; :</span>
<span class="hl slc"># arch() =~ /^ppc/ ? &quot;processor&quot; : &quot;vendor_id&quot;</span>

<span class="hl slc"># cpu_model : arch() =~ /^alpha/ ? &quot;cpu model&quot; :</span>
<span class="hl slc"># arch() =~ /^ppc/ ? &quot;cpu  &quot; : &quot;model name&quot;</span>

<span class="hl slc"># cpu_freq = arch() =~ /^alpha/ ? &quot;cycle frequency [Hz]&quot; :</span>
<span class="hl slc"># arch() =~ /^ppc/ ? &quot;clock&quot; : &quot;cpu MHz&quot;</span>

<span class="hl kwa">sub</span> getCPUs<span class="hl opt">() {</span> 
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">&#64;cpus, $cpu</span><span class="hl opt">);</span>
    <span class="hl kwa">foreach</span> <span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&quot;/proc/cpuinfo&quot;</span><span class="hl opt">)) {</span>
	   <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwd">/^processor/</span><span class="hl opt">) {</span> <span class="hl slc"># ix86 specific</span>
		  <span class="hl kwc">push</span> <span class="hl kwb">&#64;cpus, $cpu</span> <span class="hl kwa">if</span> <span class="hl kwb">$cpu</span><span class="hl opt">;</span>
		  <span class="hl kwb">$cpu</span> <span class="hl opt">= {};</span>
	   <span class="hl opt">}</span>
	   <span class="hl kwb">$cpu</span><span class="hl opt">-&gt;{</span><span class="hl kwb">$1</span><span class="hl opt">} =</span> <span class="hl kwb">$2</span> <span class="hl kwa">if</span> <span class="hl kwd">/^([^\t]+).*:\s(.*)$/</span><span class="hl opt">;</span>
	   <span class="hl kwb">$cpu</span><span class="hl opt">-&gt;{</span>processor<span class="hl opt">}++</span> <span class="hl kwa">if</span> <span class="hl kwb">$1</span> <span class="hl kwc">eq</span> <span class="hl str">&quot;processor&quot;</span><span class="hl opt">;</span>
    <span class="hl opt">}</span>
    <span class="hl kwc">push</span> <span class="hl kwb">&#64;cpus, $cpu</span><span class="hl opt">;</span>
    <span class="hl kwb">&#64;cpus</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> ix86_cpu_frequency<span class="hl opt">() {</span>
    cat_<span class="hl opt">(</span><span class="hl str">&apos;/proc/cpuinfo&apos;</span><span class="hl opt">) =~</span> <span class="hl kwd">/cpu MHz\s*:\s*(\d+)/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> probe_category <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$category</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>

    <span class="hl kwa">require</span> list_modules<span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;modules</span> <span class="hl opt">=</span> list_modules<span class="hl opt">::</span>category2modules<span class="hl opt">(</span><span class="hl kwb">$category</span><span class="hl opt">);</span>

    if_<span class="hl opt">(</span><span class="hl kwb">$category</span> <span class="hl opt">=~</span> <span class="hl kwd">/sound/</span> <span class="hl opt">&amp;&amp;</span> arch<span class="hl opt">() =~</span> <span class="hl kwd">/ppc/</span> <span class="hl opt">&amp;&amp;</span> get_mac_model<span class="hl opt">() !~</span> <span class="hl kwd">/IBM/</span><span class="hl opt">,</span>
	<span class="hl opt">{</span> driver <span class="hl opt">=&gt;</span> <span class="hl str">&apos;snd_powermac&apos;</span><span class="hl opt">,</span> description <span class="hl opt">=&gt;</span> <span class="hl str">&apos;Macintosh built-in&apos;</span> <span class="hl opt">},</span>
    <span class="hl opt">),</span>
    <span class="hl kwc">grep</span> <span class="hl opt">{</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$category</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;network/isdn&apos;</span><span class="hl opt">) {</span>
	    <span class="hl kwc">my</span> <span class="hl kwb">$b</span> <span class="hl opt">=</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =~</span> <span class="hl kwd">/ISDN:([^,]*),?([^,]*)(?:,firmware=(.*))?/</span><span class="hl opt">;</span>
	    <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$b</span><span class="hl opt">) {</span>
                <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>
                <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>type<span class="hl opt">} =</span> <span class="hl kwb">$2</span><span class="hl opt">;</span>
                <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>type<span class="hl opt">} =~</span> <span class="hl kwd">s/type=//</span><span class="hl opt">;</span>
                <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>firmware<span class="hl opt">} =</span> <span class="hl kwb">$3</span><span class="hl opt">;</span>
                <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&quot;hisax&quot;</span> <span class="hl kwc">and</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>options<span class="hl opt">} .=</span> <span class="hl str">&quot; id=HiSax&quot;</span><span class="hl opt">;</span>
	    <span class="hl opt">}</span>
	    <span class="hl kwb">$b</span><span class="hl opt">;</span>
	<span class="hl opt">}</span> <span class="hl kwa">else</span> <span class="hl opt">{</span>
	    member<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">},</span> <span class="hl kwb">&#64;modules</span><span class="hl opt">);</span>
	<span class="hl opt">}</span>
    <span class="hl opt">}</span> probeall<span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> getSoundDevices<span class="hl opt">() {</span>
    probe_category<span class="hl opt">(</span><span class="hl str">&apos;multimedia/sound&apos;</span><span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> isTVcardConfigurable <span class="hl opt">{</span> member<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]{</span>driver<span class="hl opt">},</span> <span class="hl str">qw(bttv cx88 saa7134)</span><span class="hl opt">) }</span>

<span class="hl kwa">sub</span> getTVcards<span class="hl opt">() {</span> probe_category<span class="hl opt">(</span><span class="hl str">&apos;multimedia/tv&apos;</span><span class="hl opt">) }</span>

<span class="hl kwa">sub</span> getInputDevices<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">&#64;devices, $device</span><span class="hl opt">);</span>
    <span class="hl kwa">foreach</span> <span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&apos;/proc/bus/input/devices&apos;</span><span class="hl opt">)) {</span>
        <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwd">/^I:/</span><span class="hl opt">) {</span>
            <span class="hl kwb">$device</span> <span class="hl opt">= {};</span>
            <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>vendor<span class="hl opt">} =</span> <span class="hl kwd">/Vendor=(\w+)/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>
            <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>id<span class="hl opt">} =</span> <span class="hl kwd">/Product=(\w+)/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>
            <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>bustype<span class="hl opt">} =</span> <span class="hl kwd">/Bus=(\w+)/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>
        <span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwd">/N: Name=&quot;(.*)&quot;/</span><span class="hl opt">) {</span>
	    <span class="hl kwc">my</span> <span class="hl kwb">$descr</span> <span class="hl opt">=</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>
	    <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>description<span class="hl opt">} =</span> <span class="hl str">&quot;|</span><span class="hl ipl">$descr</span><span class="hl str">&quot;</span><span class="hl opt">;</span>

	    <span class="hl slc">#- I: Bus=0011 Vendor=0002 Product=0008 Version=7321</span>
	    <span class="hl slc">#- N: Name=&quot;AlpsPS/2 ALPS GlidePoint&quot;</span>
	    <span class="hl slc">#- P: Phys=isa0060/serio1/input0</span>
	    <span class="hl slc">#- H: Handlers=mouse1 event2 ts1</span>
	    <span class="hl slc">#- B: EV=f</span>
	    <span class="hl slc">#- B: KEY=420 0 70000 0 0 0 0 0 0 0 0 #=&gt; BTN_LEFT BTN_RIGHT BTN_MIDDLE BTN_TOOL_FINGER BTN_TOUCH</span>
	    <span class="hl slc">#-    or B: KEY=420 0 670000 0 0 0 0 0 0 0 0 #=&gt; same with BTN_BACK</span>
	    <span class="hl slc">#- B: REL=3       #=&gt; X Y</span>
	    <span class="hl slc">#- B: ABS=1000003 #=&gt; X Y PRESSURE</span>

	    <span class="hl slc">#- I: Bus=0011 Vendor=0002 Product=0008 Version=2222</span>
	    <span class="hl slc">#- N: Name=&quot;AlpsPS/2 ALPS DualPoint TouchPad&quot;</span>
	    <span class="hl slc">#- P: Phys=isa0060/serio1/input0</span>
	    <span class="hl slc">#- S: Sysfs=/class/input/input2</span>
	    <span class="hl slc">#- H: Handlers=mouse1 ts1 event2 </span>
	    <span class="hl slc">#- B: EV=f</span>
	    <span class="hl slc">#- B: KEY=420 0 70000 0 0 0 0 0 0 0 0</span>
	    <span class="hl slc">#- B: REL=3</span>
	    <span class="hl slc">#- B: ABS=1000003</span>

	    <span class="hl slc">#- I: Bus=0011 Vendor=0002 Product=0007 Version=0000</span>
	    <span class="hl slc">#- N: Name=&quot;SynPS/2 Synaptics TouchPad&quot;</span>
	    <span class="hl slc">#- P: Phys=isa0060/serio1/input0</span>
	    <span class="hl slc">#- S: Sysfs=/class/input/input1</span>
	    <span class="hl slc">#- H: Handlers=mouse0 event1 ts0</span>
	    <span class="hl slc">#- B: EV=b</span>
	    <span class="hl slc">#- B: KEY=6420 0 70000 0 0 0 0 0 0 0 0 #=&gt; BTN_LEFT BTN_RIGHT BTN_MIDDLE BTN_TOOL_FINGER BTN_TOUCH BTN_TOOL_DOUBLETAP BTN_TOOL_TRIPLETAP</span>
	    <span class="hl slc">#-    or B: KEY=6420 0 670000 0 0 0 0 0 0 0 0  #=&gt; same with BTN_BACK</span>
	    <span class="hl slc">#-    or B: KEY=420 30000 670000 0 0 0 0 0 0 0 0 #=&gt; same without BTN_TOOL_TRIPLETAP but with BTN_B</span>
	    <span class="hl slc">#- B: ABS=11000003 #=&gt; X Y PRESSURE TOOL_WIDTH</span>

	    <span class="hl slc">#- I: Bus=0003 Vendor=056a Product=0065 Version=0108</span>
	    <span class="hl slc">#- N: Name=&quot;Wacom Bamboo&quot;</span>
	    <span class="hl slc">#- B: KEY=1c63 0 70033 0 0 0 0 0 0 0 0 #=&gt; BTN_0 BTN_1 BTN_4 BTN_5 BTN_LEFT BTN_RIGHT BTN_MIDDLE TOOL_PEN TOOL_RUBBER TOOL_BRUSH TOOL_FINGER TOOL_MOUSE TOUCH STYLUS STYLUS2</span>
            <span class="hl slc">#- B: ABS=100 3000103 #=&gt; X Y WHEEL PRESSURE DISTANCE MISC</span>

	    <span class="hl slc">#- I: Bus=0003 Vendor=056a Product=0011 Version=0201</span>
	    <span class="hl slc">#- N: Name=&quot;Wacom Graphire2 4x5&quot;</span>
            <span class="hl slc">#- B: KEY=1c43 0 70000 0 0 0 0 0 0 0 0 #=&gt; BTN_LEFT BTN_RIGHT BTN_MIDDLE TOOL_PEN TOOL_RUBBER TOOL_FINGER TOOL_MOUSE TOUCH STYLUS STYLUS2</span>
            <span class="hl slc">#- B: ABS=100 3000003 #=&gt; X Y PRESSURE DISTANCE MISC</span>

	    <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>Synaptics<span class="hl opt">} =</span> <span class="hl kwb">$descr</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;SynPS/2 Synaptics TouchPad&apos;</span><span class="hl opt">;</span>
	    <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>ALPS<span class="hl opt">} =</span> <span class="hl kwb">$descr</span> <span class="hl opt">=~</span> <span class="hl kwd">m!^AlpsPS/2 ALPS!</span><span class="hl opt">;</span>
	    <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>Elantech<span class="hl opt">} =</span> <span class="hl kwb">$descr</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;ETPS/2 Elantech Touchpad&apos;</span><span class="hl opt">;</span>

	<span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwd">/H: Handlers=(.*)/</span><span class="hl opt">) {</span>
	    <span class="hl kwc">my</span> <span class="hl kwb">&#64;l</span> <span class="hl opt">=</span> <span class="hl kwc">split</span><span class="hl opt">(</span><span class="hl str">&apos; &apos;</span><span class="hl opt">,</span> <span class="hl kwb">$1</span><span class="hl opt">);</span>
	    <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =</span> <span class="hl kwb">$l</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">];</span> <span class="hl slc">#- keep it for compatibility</span>
	    <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>Handlers<span class="hl opt">} = +{</span> <span class="hl kwc">map</span> <span class="hl opt">{ (</span><span class="hl kwd">/^(.*?)\d*$/</span> ? <span class="hl kwb">$1</span> <span class="hl opt">:</span> <span class="hl kwb">$_, $_</span><span class="hl opt">) }</span> <span class="hl kwc">split</span><span class="hl opt">(</span><span class="hl str">&apos; &apos;</span><span class="hl opt">,</span> <span class="hl kwb">$1</span><span class="hl opt">) };</span>
	<span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwd">/S: Sysfs=(.+)/</span><span class="hl opt">) {</span>
	    <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>sysfs_path<span class="hl opt">} =</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>
	<span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwd">/P: Phys=(.*)/</span><span class="hl opt">) {</span>
            <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>location<span class="hl opt">} =</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>
            <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>bus<span class="hl opt">} =</span> <span class="hl str">&apos;isa&apos;</span> <span class="hl kwa">if</span> <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>location<span class="hl opt">} =~</span> <span class="hl kwd">/^isa/</span><span class="hl opt">;</span>
            <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>bus<span class="hl opt">} =</span> <span class="hl str">&apos;usb&apos;</span> <span class="hl kwa">if</span> <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>location<span class="hl opt">} =~</span> <span class="hl kwd">/^usb/i</span><span class="hl opt">;</span>
	<span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwd">/B: REL=(.* )?(.*)/</span><span class="hl opt">) {</span>
	    <span class="hl slc">#- REL=3   #=&gt; X Y</span>
	    <span class="hl slc">#- REL=103 #=&gt; X Y WHEEL</span>
	    <span class="hl slc">#- REL=143 #=&gt; X Y HWHEEL WHEEL</span>
	    <span class="hl slc">#- REL=1c3 #=&gt; X Y HWHEEL DIAL WHEEL</span>
	    <span class="hl kwc">my</span> <span class="hl kwb">$REL</span> <span class="hl opt">=</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$2</span><span class="hl opt">);</span>
	    <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>HWHEEL<span class="hl opt">} =</span> <span class="hl num">1</span> <span class="hl kwa">if</span> <span class="hl kwb">$REL</span> <span class="hl opt">&amp; (</span><span class="hl num">1</span> <span class="hl opt">&lt;&lt;</span> <span class="hl num">6</span><span class="hl opt">);</span>
	    <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>WHEEL<span class="hl opt">} =</span> <span class="hl num">1</span> <span class="hl kwa">if</span> <span class="hl kwb">$REL</span> <span class="hl opt">&amp; (</span><span class="hl num">1</span> <span class="hl opt">&lt;&lt;</span> <span class="hl num">8</span><span class="hl opt">);</span> <span class="hl slc">#- not reliable (&quot;Mitsumi Apple USB Mouse&quot; says REL=103 and KEY=1f0000 ...)</span>

	<span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwd">/B: KEY=(\S+)/</span><span class="hl opt">) {</span>	   
	    <span class="hl slc">#- some KEY explained:</span>
	    <span class="hl slc">#- (but note that BTN_MIDDLE can be reported even if missing)</span>
	    <span class="hl slc">#- (and &quot;Mitsumi Apple USB Mouse&quot; reports 1f0000)</span>
	    <span class="hl slc">#- KEY=30000 0 0 0 0 0 0 0 0  #=&gt; BTN_LEFT BTN_RIGHT</span>
	    <span class="hl slc">#- KEY=70000 0 0 0 0 0 0 0 0  #=&gt; BTN_LEFT BTN_RIGHT BTN_MIDDLE</span>
	    <span class="hl slc">#- KEY=1f0000 0 0 0 0 0 0 0 0 #=&gt; BTN_LEFT BTN_RIGHT BTN_MIDDLE BTN_SIDE BTN_EXTRA</span>
	    <span class="hl kwc">my</span> <span class="hl kwb">$KEY</span> <span class="hl opt">=</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$1</span><span class="hl opt">);</span>
	    <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span>SIDE<span class="hl opt">} =</span> <span class="hl num">1</span> <span class="hl kwa">if</span> <span class="hl kwb">$KEY</span> <span class="hl opt">&amp; (</span><span class="hl num">1</span> <span class="hl opt">&lt;&lt;</span> <span class="hl num">0x13</span><span class="hl opt">);</span>

        <span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwd">/^\s*$/</span><span class="hl opt">) {</span>
	    <span class="hl kwc">push</span> <span class="hl kwb">&#64;devices, $device</span> <span class="hl kwa">if</span> <span class="hl kwb">$device</span><span class="hl opt">;</span>
	    <span class="hl kwc">undef</span> <span class="hl kwb">$device</span><span class="hl opt">;</span>
	<span class="hl opt">}</span>
    <span class="hl opt">}</span>
    <span class="hl kwb">&#64;devices</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> getInputDevices_and_usb<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;l</span> <span class="hl opt">=</span> getInputDevices<span class="hl opt">();</span>

    <span class="hl kwa">foreach</span> <span class="hl kwc">my</span> <span class="hl kwb">$usb</span> <span class="hl opt">(</span>usb_probe<span class="hl opt">()) {</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwc">my</span> <span class="hl kwb">$e</span> <span class="hl opt">=</span> find <span class="hl opt">{</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>vendor<span class="hl opt">}) ==</span> <span class="hl kwb">$usb</span><span class="hl opt">-&gt;{</span>vendor<span class="hl opt">} &amp;&amp;</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>id<span class="hl opt">}) ==</span> <span class="hl kwb">$usb</span><span class="hl opt">-&gt;{</span>id<span class="hl opt">} }</span> <span class="hl kwb">&#64;l</span><span class="hl opt">) {</span>
	    <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>usb<span class="hl opt">} =</span> <span class="hl kwb">$usb</span><span class="hl opt">;</span>
	<span class="hl opt">}</span>
    <span class="hl opt">}</span>

    <span class="hl kwb">&#64;l</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> serialPorts<span class="hl opt">() {</span> <span class="hl kwc">map</span> <span class="hl opt">{</span> <span class="hl str">&quot;ttyS</span><span class="hl ipl">$_</span><span class="hl str">&quot;</span> <span class="hl opt">}</span> <span class="hl num">0</span><span class="hl opt">.</span><span class="hl num">.7</span> <span class="hl opt">}</span>
<span class="hl kwa">sub</span> serialPort2text <span class="hl opt">{</span>
    <span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">] =~</span> <span class="hl kwd">/ttyS(\d+)/</span> ? <span class="hl str">&quot;</span><span class="hl ipl">$_</span><span class="hl str">[0] / COM&quot;</span> <span class="hl opt">. (</span><span class="hl kwb">$1</span> <span class="hl opt">+</span> <span class="hl num">1</span><span class="hl opt">) :</span> <span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">];</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> getSerialModem <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$modules_conf, $o_mouse</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$mouse</span> <span class="hl opt">=</span> <span class="hl kwb">$o_mouse</span> <span class="hl opt">|| {};</span>
    <span class="hl kwb">$mouse</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">} =</span> <span class="hl kwc">readlink</span> <span class="hl str">&quot;/dev/mouse&quot;</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$serdev</span> <span class="hl opt">=</span> arch<span class="hl opt">() =~</span> <span class="hl kwd">/ppc/</span> ? <span class="hl str">&quot;macserial&quot;</span> <span class="hl opt">:</span> <span class="hl str">&quot;serial&quot;</span><span class="hl opt">;</span>
    <span class="hl kwc">eval</span> <span class="hl opt">{</span> modules<span class="hl opt">::</span>load<span class="hl opt">(</span><span class="hl kwb">$serdev</span><span class="hl opt">) };</span>

    <span class="hl kwc">my</span> <span class="hl kwb">&#64;modems</span><span class="hl opt">;</span>

    probeSerialDevices<span class="hl opt">();</span>
    <span class="hl kwa">foreach</span> <span class="hl kwc">my</span> <span class="hl kwb">$port</span> <span class="hl opt">(</span>serialPorts<span class="hl opt">()) {</span>
	<span class="hl kwa">next if</span> <span class="hl kwb">$mouse</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">} =~</span> <span class="hl kwd">/$port/</span><span class="hl opt">;</span>
     <span class="hl kwc">my</span> <span class="hl kwb">$device</span> <span class="hl opt">=</span> <span class="hl str">&quot;/dev/</span><span class="hl ipl">$port</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
	<span class="hl kwa">next if</span> <span class="hl opt">!-</span>e <span class="hl kwb">$device</span> <span class="hl opt">|| !</span>hasModem<span class="hl opt">(</span><span class="hl kwb">$device</span><span class="hl opt">);</span>
     <span class="hl kwb">$serialprobe</span><span class="hl opt">{</span><span class="hl kwb">$device</span><span class="hl opt">}{</span>device<span class="hl opt">} =</span> <span class="hl kwb">$device</span><span class="hl opt">;</span>
     <span class="hl kwc">push</span> <span class="hl kwb">&#64;modems, $serialprobe</span><span class="hl opt">{</span><span class="hl kwb">$device</span><span class="hl opt">};</span>
    <span class="hl opt">}</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;devs</span> <span class="hl opt">=</span> pcmcia_probe<span class="hl opt">();</span>
    <span class="hl kwa">foreach</span> <span class="hl kwc">my</span> <span class="hl kwb">$modem</span> <span class="hl opt">(</span><span class="hl kwb">&#64;modems</span><span class="hl opt">) {</span>
        <span class="hl slc">#- add an alias for macserial on PPC</span>
        <span class="hl kwb">$modules_conf</span><span class="hl opt">-&gt;</span><span class="hl kwd">set_alias</span><span class="hl opt">(</span><span class="hl str">&apos;serial&apos;</span><span class="hl opt">,</span> <span class="hl kwb">$serdev</span><span class="hl opt">)</span> <span class="hl kwa">if</span> arch<span class="hl opt">() =~</span> <span class="hl kwd">/ppc/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$modem</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">};</span>
        <span class="hl kwa">foreach</span> <span class="hl opt">(</span><span class="hl kwb">&#64;devs</span><span class="hl opt">) {</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">}</span> <span class="hl kwc">and</span> <span class="hl kwb">$modem</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">} =</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">} }</span>
    <span class="hl opt">}</span>
    <span class="hl kwb">&#64;modems</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwc">our</span> <span class="hl kwb">$detect_serial_modem</span> <span class="hl opt">=</span> <span class="hl num">1</span><span class="hl opt">;</span>
<span class="hl kwa">sub</span> getModem <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$modules_conf</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl opt">(</span><span class="hl kwb">$detect_serial_modem</span> ? getSerialModem<span class="hl opt">(</span><span class="hl kwb">$modules_conf,</span> <span class="hl opt">{}) : ()),</span> get_winmodems<span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_winmodems<span class="hl opt">() {</span>
    matching_driver__regexp<span class="hl opt">(</span><span class="hl str">&apos;www\.linmodems\.org&apos;</span><span class="hl opt">),</span>
    matching_driver<span class="hl opt">(</span>list_modules<span class="hl opt">::</span>category2modules<span class="hl opt">(</span><span class="hl str">&apos;network/modem&apos;</span><span class="hl opt">),</span>
    list_modules<span class="hl opt">::</span>category2modules<span class="hl opt">(</span><span class="hl str">&apos;network/slmodem&apos;</span><span class="hl opt">));</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> getBewan<span class="hl opt">() {</span>
    matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;Bewan Systems\|.*ADSL|BEWAN ADSL USB|\[Unicorn\]&apos;</span><span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl slc"># generate from the following from eci driver sources:</span>
<span class="hl slc"># perl -e &apos;while (&lt;&gt;) { print qq(&quot;$1$2&quot;,\n&quot;$3$4&quot;,\n) if /\b([a-z\d]*)\s*([a-z\d]*)\s*([a-z\d]*)\s*([a-z\d]*)$/ }&apos; &lt;modems.db|sort|uniq</span>
<span class="hl kwa">sub</span> getECI<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;ids</span> <span class="hl opt">= (</span>
              <span class="hl str">&quot;05090801&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;05472131&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;06590915&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;071dac81&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;08ea00c9&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;09150001&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;09150002&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;091500ca&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;091500e7&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;09150101&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;09150102&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;09150204&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;09150206&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;09150802&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;09150916&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;09158000&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;09158001&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;0915ac82&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;0baf00e6&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;0e600100&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;0e600101&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;0fe88000&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;16900203&quot;</span><span class="hl opt">,</span>
              <span class="hl str">&quot;16900205&quot;</span><span class="hl opt">,</span>
             <span class="hl opt">);</span>
    <span class="hl kwc">grep</span> <span class="hl opt">{</span> member<span class="hl opt">(</span><span class="hl kwc">sprintf</span><span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">%04x%04x%04x%04x</span><span class="hl str">&quot;</span><span class="hl opt">,</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>vendor<span class="hl opt">},</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>id<span class="hl opt">},</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>subvendor<span class="hl opt">},</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>subid<span class="hl opt">}),</span> <span class="hl kwb">&#64;ids</span><span class="hl opt">) }</span> usb_probe<span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_xdsl_usb_devices<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;bewan</span> <span class="hl opt">=</span> detect_devices<span class="hl opt">::</span>getBewan<span class="hl opt">();</span>
    <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>bus<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;USB&apos;</span> ? <span class="hl str">&apos;unicorn_usb_atm&apos;</span> <span class="hl opt">:</span> <span class="hl str">&apos;unicorn_pci_atm&apos;</span> <span class="hl kwa">foreach</span> <span class="hl kwb">&#64;bewan</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;eci</span> <span class="hl opt">=</span> detect_devices<span class="hl opt">::</span>getECI<span class="hl opt">();</span>
    <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =</span> <span class="hl str">&apos;eciusb&apos;</span> <span class="hl kwa">foreach</span> <span class="hl kwb">&#64;eci</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;usb</span> <span class="hl opt">=</span> detect_devices<span class="hl opt">::</span>probe_category<span class="hl opt">(</span><span class="hl str">&apos;network/usb_dsl&apos;</span><span class="hl opt">);</span>
    <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>description<span class="hl opt">} =</span> <span class="hl str">&quot;USB ADSL modem (eagle chipset)&quot;</span> <span class="hl kwa">foreach</span>
      <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;ueagle_atm&apos;</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>description<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;(null)&apos;</span> <span class="hl opt">}</span> <span class="hl kwb">&#64;usb</span><span class="hl opt">;</span>
    <span class="hl kwb">&#64;usb, &#64;bewan, &#64;eci</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> is_lan_interface <span class="hl opt">{</span>
    <span class="hl slc">#- we want LAN like interfaces here (eg: ath|br|eth|fddi|plip|ra|tr|usb|wlan).</span>
    <span class="hl slc">#- there&apos;s also bnep%d for bluetooth, bcp%d...</span>
    <span class="hl slc">#- we do this by blacklisting the following interfaces:</span>
    <span class="hl slc">#-   hso%d are created by drivers/net/usb/hso.c</span>
    <span class="hl slc">#-   ippp|isdn|plip|ppp (initscripts suggest that isdn%d can be created but kernel sources claim not)</span>
    <span class="hl slc">#-   ippp%d are created by drivers/isdn/i4l/isdn_ppp.c</span>
    <span class="hl slc">#-   plip%d are created by drivers/net/plip.c</span>
    <span class="hl slc">#-   ppp%d are created by drivers/net/ppp_generic.c</span>
    <span class="hl slc">#-   pan%d are created by bnep</span>
    is_useful_interface<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]) &amp;&amp;</span>
    <span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">] !~</span> <span class="hl kwd">/^(?:hso|ippp|isdn|plip|ppp|pan)/</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> is_useful_interface <span class="hl opt">{</span>
    <span class="hl slc">#- sit0 which is *always* created by net/ipv6/sit.c, thus is always created since net.agent loads ipv6 module</span>
    <span class="hl slc">#- wifi%d are created by 3rdparty/hostap/hostap_hw.c (pseudo statistics devices, #14523)</span>
    <span class="hl slc">#- wmaster%d are created by net/mac80211/ieee80211.c (&quot;master&quot; 802.11 device)</span>
    <span class="hl slc">#- ax*, rose*, nr*, bce* and scc* are Hamradio devices (#28776)</span>
    <span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">] !~</span> <span class="hl kwd">/^(?:lo|sit0|wifi|wmaster|ax|rose|nr|bce|scc)/</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> is_wireless_interface <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$interface</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl slc">#- some wireless drivers don&apos;t always support the SIOCGIWNAME ioctl</span>
    <span class="hl slc">#-   ralink devices need to be up to support it</span>
    <span class="hl slc">#-   wlan-ng (prism2_*) need some special tweaks to support it</span>
    <span class="hl slc">#- use sysfs as fallback to detect wireless interfaces,</span>
    <span class="hl slc">#- i.e interfaces for which get_wireless_stats() is available</span>
    c<span class="hl opt">::</span>isNetDeviceWirelessAware<span class="hl opt">(</span><span class="hl kwb">$interface</span><span class="hl opt">) || -</span>e <span class="hl str">&quot;/sys/class/net/</span><span class="hl ipl">$interface/wireless</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_all_net_devices<span class="hl opt">() {</span>
    <span class="hl slc">#- we need both detection schemes since:</span>
    <span class="hl slc">#-   get_netdevices() use the SIOCGIFCONF ioctl that does not list interfaces that are down</span>
    <span class="hl slc">#-   /proc/net/dev does not list VLAN and IP aliased interfaces</span>
    uniq<span class="hl opt">(</span>
        <span class="hl opt">(</span><span class="hl kwc">map</span> <span class="hl opt">{</span> if_<span class="hl opt">(</span><span class="hl kwd">/^\s*([A-Za-z0-9:\.]*):/</span><span class="hl opt">,</span> <span class="hl kwb">$1</span><span class="hl opt">) }</span> cat_<span class="hl opt">(</span><span class="hl str">&quot;/proc/net/dev&quot;</span><span class="hl opt">)),</span>
        c<span class="hl opt">::</span>get_netdevices<span class="hl opt">(),</span>
    <span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_lan_interfaces<span class="hl opt">() {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> is_lan_interface<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">) }</span> get_all_net_devices<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> get_net_interfaces<span class="hl opt">() {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> is_useful_interface<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">) }</span> get_all_net_devices<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> get_wireless_interface<span class="hl opt">() {</span> find <span class="hl opt">{</span> is_wireless_interface<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">) }</span> get_lan_interfaces<span class="hl opt">() }</span>

<span class="hl kwa">sub</span> is_bridge_interface <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$interface</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl opt">-</span>f <span class="hl str">&quot;/sys/class/net/</span><span class="hl ipl">$interface/bridge/bridge_id</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_ids_from_sysfs_device <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$dev_path</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$dev_cat</span> <span class="hl opt">=</span> <span class="hl kwa">sub</span> <span class="hl opt">{</span> chomp_<span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$dev_path/$_</span><span class="hl str">[0]&quot;</span><span class="hl opt">)) };</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$usb_root</span> <span class="hl opt">= -</span>f <span class="hl str">&quot;</span><span class="hl ipl">$dev_path/bInterfaceNumber</span><span class="hl str">&quot;</span> <span class="hl opt">&amp;&amp;</span> <span class="hl str">&quot;../&quot;</span> <span class="hl opt">|| -</span>f <span class="hl str">&quot;</span><span class="hl ipl">$dev_path/idVendor</span><span class="hl str">&quot;</span> <span class="hl opt">&amp;&amp;</span> <span class="hl str">&quot;&quot;</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$is_pcmcia</span> <span class="hl opt">= -</span>f <span class="hl str">&quot;</span><span class="hl ipl">$dev_path/card_id</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$sysfs_ids</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$bus</span> <span class="hl opt">=</span> get_sysfs_field_from_link<span class="hl opt">(</span><span class="hl kwb">$dev_path,</span> <span class="hl str">&quot;bus&quot;</span><span class="hl opt">);</span>
    <span class="hl slc">#- FIXME: use $bus</span>
    <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$is_pcmcia</span><span class="hl opt">) {</span>
      <span class="hl kwb">$sysfs_ids</span> <span class="hl opt">= {</span> modalias <span class="hl opt">=&gt;</span> <span class="hl kwb">$dev_cat</span><span class="hl opt">-&gt;(</span><span class="hl str">&apos;modalias&apos;</span><span class="hl opt">) };</span>
    <span class="hl opt">}</span> <span class="hl kwa">else</span> <span class="hl opt">{</span>
        <span class="hl kwb">$sysfs_ids</span> <span class="hl opt">=</span> <span class="hl kwb">$bus</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;ieee1394&apos;</span> ?
          <span class="hl opt">{</span>
            version <span class="hl opt">=&gt;</span> <span class="hl str">&quot;../vendor_id&quot;</span><span class="hl opt">,</span>
            specifier_id <span class="hl opt">=&gt;</span> <span class="hl str">&quot;specifier_id&quot;</span><span class="hl opt">,</span>
            specifier_version <span class="hl opt">=&gt;</span> <span class="hl str">&quot;version&quot;</span><span class="hl opt">,</span>
          <span class="hl opt">} :</span>
        <span class="hl kwc">defined</span> <span class="hl kwb">$usb_root</span> ?
          <span class="hl opt">{</span> id <span class="hl opt">=&gt;</span> <span class="hl kwb">$usb_root</span> <span class="hl opt">.</span> <span class="hl str">&apos;idProduct&apos;</span><span class="hl opt">,</span> vendor <span class="hl opt">=&gt;</span> <span class="hl kwb">$usb_root</span> <span class="hl opt">.</span> <span class="hl str">&apos;idVendor&apos;</span> <span class="hl opt">} :</span>
          <span class="hl opt">{</span> id <span class="hl opt">=&gt;</span> <span class="hl str">&quot;device&quot;</span><span class="hl opt">,</span> subid <span class="hl opt">=&gt;</span> <span class="hl str">&quot;subsystem_device&quot;</span><span class="hl opt">,</span> vendor <span class="hl opt">=&gt;</span> <span class="hl str">&quot;vendor&quot;</span><span class="hl opt">,</span> subvendor <span class="hl opt">=&gt;</span> <span class="hl str">&quot;subsystem_vendor&quot;</span> <span class="hl opt">};</span>
        <span class="hl kwb">$_</span> <span class="hl opt">=</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$dev_cat</span><span class="hl opt">-&gt;(</span><span class="hl kwb">$_</span><span class="hl opt">))</span> <span class="hl kwa">foreach</span> <span class="hl kwc">values</span> <span class="hl kwb">%$sysfs_ids</span><span class="hl opt">;</span>
        <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$bus</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;pci&apos;</span><span class="hl opt">) {</span>
            <span class="hl kwc">my</span> <span class="hl kwb">$device</span> <span class="hl opt">=</span> basename<span class="hl opt">(</span><span class="hl kwc">readlink</span> <span class="hl kwb">$dev_path</span><span class="hl opt">);</span>
            <span class="hl kwc">my</span> <span class="hl kwb">&#64;ids</span> <span class="hl opt">=</span> <span class="hl kwb">$device</span> <span class="hl opt">=~</span> <span class="hl kwd">/^(.{4}):(.{2}):(.{2})\.(.+)$/</span><span class="hl opt">;</span>
            <span class="hl opt">&#64;{</span><span class="hl kwb">$sysfs_ids</span><span class="hl opt">}{</span><span class="hl str">qw(pci_domain pci_bus pci_device pci_function)</span><span class="hl opt">} =</span> <span class="hl kwc">map</span> <span class="hl opt">{</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">) }</span> <span class="hl kwb">&#64;ids</span> <span class="hl kwa">if</span> <span class="hl kwb">&#64;ids</span><span class="hl opt">;</span>
        <span class="hl opt">}</span>
    <span class="hl opt">}</span>
    <span class="hl kwb">$sysfs_ids</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> device_matches_sysfs_ids <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$device, $sysfs_ids</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    every <span class="hl opt">{</span> <span class="hl kwc">defined</span> <span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span><span class="hl kwb">$_</span><span class="hl opt">} &amp;&amp;</span> member<span class="hl opt">(</span><span class="hl kwb">$device</span><span class="hl opt">-&gt;{</span><span class="hl kwb">$_</span><span class="hl opt">},</span> <span class="hl kwb">$sysfs_ids</span><span class="hl opt">-&gt;{</span><span class="hl kwb">$_</span><span class="hl opt">},</span> <span class="hl num">0xffff</span><span class="hl opt">) }</span> <span class="hl kwc">keys</span> <span class="hl kwb">%$sysfs_ids</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> device_matches_sysfs_device <span class="hl opt">{</span>
  <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$device, $dev_path</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
  device_matches_sysfs_ids<span class="hl opt">(</span><span class="hl kwb">$device,</span> get_ids_from_sysfs_device<span class="hl opt">(</span><span class="hl kwb">$dev_path</span><span class="hl opt">));</span>
<span class="hl opt">}</span>

<span class="hl slc">#sub getISDN() {</span>
<span class="hl slc">#    mapgrep(sub {member (($_[0] =~ /\s*(\w*):/), &#64;netdevices), $1 }, split(/\n/, cat_(&quot;/proc/net/dev&quot;)));</span>
<span class="hl slc">#}</span>

<span class="hl kwa">sub</span> getUPS<span class="hl opt">() {</span>
    <span class="hl slc"># MGE serial PnP devices:</span>
    <span class="hl opt">(</span><span class="hl kwc">map</span> <span class="hl opt">{</span>
        <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>port<span class="hl opt">} =</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>DEVICE<span class="hl opt">};</span>
        <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>bus<span class="hl opt">} =</span> <span class="hl str">&quot;Serial&quot;</span><span class="hl opt">;</span>
        <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =</span> <span class="hl str">&quot;mge-utalk&quot;</span> <span class="hl kwa">if</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>MODEL<span class="hl opt">} =~</span> <span class="hl kwd">/0001/</span><span class="hl opt">;</span>
        <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =</span> <span class="hl str">&quot;mge-shut&quot;</span>  <span class="hl kwa">if</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>MODEL<span class="hl opt">} =~</span> <span class="hl kwd">/0002/</span><span class="hl opt">;</span>
        <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">} =</span> <span class="hl str">&apos;UPS&apos;</span><span class="hl opt">;</span>
        <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>description<span class="hl opt">} =</span> <span class="hl str">&quot;MGE UPS SYSTEMS|UPS - Uninterruptible Power Supply&quot;</span> <span class="hl kwa">if</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>MODEL<span class="hl opt">} =~</span> <span class="hl kwd">/000[12]/</span><span class="hl opt">;</span>
        <span class="hl kwb">$_</span><span class="hl opt">;</span>
    <span class="hl opt">}</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>DESCRIPTION<span class="hl opt">} =~</span> <span class="hl kwd">/MGE UPS/</span> <span class="hl opt">}</span> <span class="hl kwc">values</span> <span class="hl kwb">%serialprobe</span><span class="hl opt">),</span>
    <span class="hl slc"># USB UPSs;</span>
    <span class="hl opt">(</span><span class="hl kwc">map</span> <span class="hl opt">{ (</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>name<span class="hl opt">} =</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>description<span class="hl opt">}) =~</span> <span class="hl kwd">s/.*\|//</span><span class="hl opt">;</span> <span class="hl kwb">$_</span> <span class="hl opt">}</span>
        <span class="hl kwc">map</span> <span class="hl opt">{</span>
            <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>description<span class="hl opt">} =~</span> <span class="hl kwd">/^American Power Conversion\|Back-UPS/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;usbhid&apos;</span><span class="hl opt">) {</span>
                <span class="hl slc">#- FIXME: should not be hardcoded, use $_-&gt;{sysfs_device} . */usb:(hiddev\d+)</span>
                <span class="hl slc">#- the device should also be assigned to the ups user</span>
                <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>port<span class="hl opt">} =</span> <span class="hl str">&quot;/dev/hiddev0&quot;</span><span class="hl opt">;</span>
                <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =</span> <span class="hl str">&apos;hidups&apos;</span><span class="hl opt">;</span>
                <span class="hl kwb">$_</span><span class="hl opt">;</span>
            <span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>description<span class="hl opt">} =~</span> <span class="hl kwd">/^MGE UPS Systems\|/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =~</span> <span class="hl kwd">/ups$/</span><span class="hl opt">) {</span>
                <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>port<span class="hl opt">} =</span> <span class="hl str">&quot;auto&quot;</span><span class="hl opt">;</span>
                <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">} =</span> <span class="hl str">&apos;UPS&apos;</span><span class="hl opt">;</span>
                <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =</span> <span class="hl str">&apos;newhidups&apos;</span><span class="hl opt">;</span>
                <span class="hl kwb">$_</span><span class="hl opt">;</span>
            <span class="hl opt">}</span> <span class="hl kwa">else</span> <span class="hl opt">{</span>
                <span class="hl opt">();</span>
            <span class="hl opt">}</span>
        <span class="hl opt">}</span> usb_probe<span class="hl opt">());</span>
<span class="hl opt">}</span>

<span class="hl kwb">$pcitable_addons</span> <span class="hl opt">=</span> <span class="hl str">&lt;&lt;&apos;EOF&apos;;</span>
<span class="hl str"># add here lines conforming the pcitable format (0xXXXX</span><span class="hl esc">\t</span><span class="hl str">0xXXXX</span><span class="hl esc">\t</span><span class="hl str">&quot;\w+&quot;</span><span class="hl esc">\t</span><span class="hl str">&quot;.*&quot;)</span>
<span class="hl str">EOF</span>

<span class="hl kwb">$usbtable_addons</span> <span class="hl opt">=</span> <span class="hl str">&lt;&lt;&apos;EOF&apos;;</span>
<span class="hl str"># add here lines conforming the usbtable format (0xXXXX</span><span class="hl esc">\t</span><span class="hl str">0xXXXX</span><span class="hl esc">\t</span><span class="hl str">&quot;\w+&quot;</span><span class="hl esc">\t</span><span class="hl str">&quot;.*&quot;)</span>
<span class="hl str">EOF</span>

<span class="hl kwa">sub</span> install_addons <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$prefix</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>

    <span class="hl slc">#- this test means install_addons can only be called after ldetect-lst has been installed.</span>
    <span class="hl kwa">if</span> <span class="hl opt">(-</span>d <span class="hl str">&quot;</span><span class="hl ipl">$prefix/usr/share/ldetect</span><span class="hl str">-lst&quot;</span><span class="hl opt">) {</span>
	<span class="hl kwc">my</span> <span class="hl kwb">$update</span> <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">;</span>
	<span class="hl kwa">foreach</span> <span class="hl opt">([</span> <span class="hl str">&apos;pcitable.d&apos;</span><span class="hl opt">,</span> <span class="hl kwb">$pcitable_addons</span> <span class="hl opt">], [</span> <span class="hl str">&apos;usbtable.d&apos;</span><span class="hl opt">,</span> <span class="hl kwb">$usbtable_addons</span> <span class="hl opt">]) {</span>
	    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$dir, $str</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;$_</span><span class="hl opt">;</span>
	    <span class="hl opt">-</span>d <span class="hl str">&quot;</span><span class="hl ipl">$prefix/usr/share/ldetect</span><span class="hl str">-lst/</span><span class="hl ipl">$dir</span><span class="hl str">&quot;</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$str</span> <span class="hl opt">=~</span> <span class="hl kwd">/^[^#]/m</span> <span class="hl kwc">and</span> <span class="hl kwb">$update</span> <span class="hl opt">=</span> <span class="hl num">1</span> <span class="hl kwc">and</span>
	      output <span class="hl str">&quot;</span><span class="hl ipl">$prefix/usr/share/ldetect</span><span class="hl str">-lst/</span><span class="hl ipl">$dir/95drakx</span><span class="hl str">.lst&quot;</span><span class="hl opt">,</span> <span class="hl kwb">$str</span><span class="hl opt">;</span>
	<span class="hl opt">}</span>
	<span class="hl kwb">$update</span> <span class="hl kwc">and</span> run_program<span class="hl opt">::</span>rooted<span class="hl opt">(</span><span class="hl kwb">$prefix,</span> <span class="hl str">&quot;/usr/sbin/update-ldetect-lst&quot;</span><span class="hl opt">);</span>
    <span class="hl opt">}</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> add_addons <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$addons, &#64;l</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>

    <span class="hl kwa">foreach</span> <span class="hl opt">(</span><span class="hl kwc">split</span> <span class="hl str">&quot;</span><span class="hl esc">\n</span><span class="hl str">&quot;</span><span class="hl opt">,</span> <span class="hl kwb">$addons</span><span class="hl opt">) {</span>
	<span class="hl kwd">/^\s/</span> <span class="hl kwc">and die</span> <span class="hl str">qq(bad detect_devices::probeall_addons line &quot;</span><span class="hl ipl">$_</span><span class="hl str">&quot;)</span><span class="hl opt">;</span>
	<span class="hl kwd">s/^#.*//</span><span class="hl opt">;</span>
	<span class="hl kwd">s/&quot;(.*?)&quot;/$1/g</span><span class="hl opt">;</span>
	<span class="hl kwa">next if</span> <span class="hl kwd">/^$/</span><span class="hl opt">;</span>
	<span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$vendor, $id, $driver, $description</span><span class="hl opt">) =</span> <span class="hl kwc">split</span><span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl esc">\t</span><span class="hl str">&quot;</span><span class="hl opt">,</span> <span class="hl kwb">$_,</span> <span class="hl num">4</span><span class="hl opt">)</span> <span class="hl kwc">or die</span> <span class="hl str">qq(bad detect_devices::probeall_addons line &quot;</span><span class="hl ipl">$_</span><span class="hl str">&quot;)</span><span class="hl opt">;</span>
	<span class="hl kwa">foreach</span> <span class="hl opt">(</span><span class="hl kwb">&#64;l</span><span class="hl opt">) {</span>
	    <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>vendor<span class="hl opt">} ==</span> <span class="hl kwc">hex</span> <span class="hl kwb">$vendor</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>id<span class="hl opt">} ==</span> <span class="hl kwc">hex</span> <span class="hl kwb">$id</span> <span class="hl kwc">or</span> <span class="hl kwa">next</span><span class="hl opt">;</span>
	    put_in_hash<span class="hl opt">(</span><span class="hl kwb">$_,</span> <span class="hl opt">{</span> driver <span class="hl opt">=&gt;</span> <span class="hl kwb">$driver,</span> description <span class="hl opt">=&gt;</span> <span class="hl kwb">$description</span> <span class="hl opt">});</span>
	<span class="hl opt">}</span>
    <span class="hl opt">}</span>
    <span class="hl kwb">&#64;l</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">&#64;pci, &#64;usb</span><span class="hl opt">);</span>
<span class="hl kwa">sub</span> pci_probe__real<span class="hl opt">() {</span>
    add_addons<span class="hl opt">(</span><span class="hl kwb">$pcitable_addons,</span> <span class="hl kwc">map</span> <span class="hl opt">{</span>
	<span class="hl kwc">my</span> <span class="hl kwb">%l</span><span class="hl opt">;</span>
	<span class="hl kwb">&#64;l</span><span class="hl opt">{</span><span class="hl str">qw(vendor id subvendor subid pci_domain pci_bus pci_device pci_function media_type nice_media_type driver description)</span><span class="hl opt">} =</span> <span class="hl kwc">split</span> <span class="hl str">&quot;</span><span class="hl esc">\t</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
	<span class="hl kwb">$l</span><span class="hl opt">{</span><span class="hl kwb">$_</span><span class="hl opt">} =</span> <span class="hl kwc">hex</span> <span class="hl kwb">$l</span><span class="hl opt">{</span><span class="hl kwb">$_</span><span class="hl opt">}</span> <span class="hl kwa">foreach</span> <span class="hl str">qw(vendor id subvendor subid)</span><span class="hl opt">;</span>
	<span class="hl kwb">$l</span><span class="hl opt">{</span>bus<span class="hl opt">} =</span> <span class="hl str">&apos;PCI&apos;</span><span class="hl opt">;</span>
	<span class="hl kwb">$l</span><span class="hl opt">{</span>sysfs_device<span class="hl opt">} =</span> <span class="hl kwc">sprintf</span><span class="hl opt">(</span><span class="hl str">&apos;/sys/bus/pci/devices/</span><span class="hl ipl">%04x</span><span class="hl str">:</span><span class="hl ipl">%02x</span><span class="hl str">:</span><span class="hl ipl">%02x</span><span class="hl str">.</span><span class="hl ipl">%d</span><span class="hl str">&apos;</span><span class="hl opt">,</span> <span class="hl kwb">$l</span><span class="hl opt">{</span>pci_domain<span class="hl opt">},</span> <span class="hl kwb">$l</span><span class="hl opt">{</span>pci_bus<span class="hl opt">},</span> <span class="hl kwb">$l</span><span class="hl opt">{</span>pci_device<span class="hl opt">},</span> <span class="hl kwb">$l</span><span class="hl opt">{</span>pci_function<span class="hl opt">});</span>
	\<span class="hl kwb">%l</span><span class="hl opt">;</span>
    <span class="hl opt">}</span> c<span class="hl opt">::</span>pci_probe<span class="hl opt">());</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> pci_probe<span class="hl opt">() {</span>
    <span class="hl kwb">&#64;pci</span> <span class="hl opt">=</span> pci_probe__real<span class="hl opt">()</span> <span class="hl kwa">if</span> <span class="hl opt">!</span><span class="hl kwb">&#64;pci</span><span class="hl opt">;</span>
    <span class="hl kwb">&#64;pci</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> usb_probe__real<span class="hl opt">() {</span>
    <span class="hl opt">-</span>e <span class="hl str">&quot;/proc/bus/usb/devices&quot;</span> <span class="hl kwc">or</span> <span class="hl kwa">return</span><span class="hl opt">;</span>

    add_addons<span class="hl opt">(</span><span class="hl kwb">$usbtable_addons,</span> <span class="hl kwc">map</span> <span class="hl opt">{</span>
	<span class="hl kwc">my</span> <span class="hl kwb">%l</span><span class="hl opt">;</span>
	<span class="hl kwb">&#64;l</span><span class="hl opt">{</span><span class="hl str">qw(vendor id media_type driver description pci_bus pci_device)</span><span class="hl opt">} =</span> <span class="hl kwc">split</span> <span class="hl str">&quot;</span><span class="hl esc">\t</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
	<span class="hl kwb">$l</span><span class="hl opt">{</span>media_type<span class="hl opt">} =</span> <span class="hl kwc">join</span><span class="hl opt">(</span><span class="hl str">&apos;|&apos;</span><span class="hl opt">,</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span> <span class="hl kwc">ne</span> <span class="hl str">&apos;(null)&apos;</span> <span class="hl opt">}</span> <span class="hl kwc">split</span><span class="hl opt">(</span><span class="hl str">&apos;\|&apos;</span><span class="hl opt">,</span> <span class="hl kwb">$l</span><span class="hl opt">{</span>media_type<span class="hl opt">}));</span>
	<span class="hl kwb">$l</span><span class="hl opt">{</span><span class="hl kwb">$_</span><span class="hl opt">} =</span> <span class="hl kwc">hex</span> <span class="hl kwb">$l</span><span class="hl opt">{</span><span class="hl kwb">$_</span><span class="hl opt">}</span> <span class="hl kwa">foreach</span> <span class="hl str">qw(vendor id)</span><span class="hl opt">;</span>
	<span class="hl kwb">$l</span><span class="hl opt">{</span>sysfs_device<span class="hl opt">} =</span> <span class="hl str">&quot;/sys/class/usb_device/usbdev</span><span class="hl ipl">$l</span><span class="hl str">{pci_bus}.</span><span class="hl ipl">$l</span><span class="hl str">{pci_device}/device&quot;</span><span class="hl opt">;</span>
	<span class="hl kwb">$l</span><span class="hl opt">{</span>bus<span class="hl opt">} =</span> <span class="hl str">&apos;USB&apos;</span><span class="hl opt">;</span>
	\<span class="hl kwb">%l</span><span class="hl opt">;</span>
    <span class="hl opt">}</span> c<span class="hl opt">::</span>usb_probe<span class="hl opt">());</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> usb_probe<span class="hl opt">() {</span>
    <span class="hl kwa">if</span> <span class="hl opt">($::</span>isStandalone <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">&#64;usb</span><span class="hl opt">) {</span>
	    <span class="hl kwb">&#64;usb</span><span class="hl opt">;</span>
    <span class="hl opt">}</span> <span class="hl kwa">else</span> <span class="hl opt">{</span>
	    <span class="hl kwb">&#64;usb</span> <span class="hl opt">=</span> usb_probe__real<span class="hl opt">();</span>
    <span class="hl opt">}</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> firewire_probe<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$dev_dir</span> <span class="hl opt">=</span> <span class="hl str">&apos;/sys/bus/ieee1394/devices&apos;</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;l</span> <span class="hl opt">=</span> <span class="hl kwc">map</span> <span class="hl opt">{</span>
        <span class="hl kwc">my</span> <span class="hl kwb">$dir</span> <span class="hl opt">=</span> <span class="hl str">&quot;</span><span class="hl ipl">$dev_dir/$_</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
        <span class="hl kwc">my</span> <span class="hl kwb">$get</span> <span class="hl opt">=</span> <span class="hl kwa">sub</span> <span class="hl opt">{</span> chomp_<span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">])) };</span>
        <span class="hl opt">{</span>
            version <span class="hl opt">=&gt;</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$get</span><span class="hl opt">-&gt;(</span><span class="hl str">&quot;</span><span class="hl ipl">$dir/</span><span class="hl str">../vendor_id&quot;</span><span class="hl opt">)),</span>
            specifier_id <span class="hl opt">=&gt;</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$get</span><span class="hl opt">-&gt;(</span><span class="hl str">&quot;</span><span class="hl ipl">$dir/specifier_id</span><span class="hl str">&quot;</span><span class="hl opt">)),</span>
            specifier_version <span class="hl opt">=&gt;</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$get</span><span class="hl opt">-&gt;(</span><span class="hl str">&quot;</span><span class="hl ipl">$dir/version</span><span class="hl str">&quot;</span><span class="hl opt">)),</span>
            bus <span class="hl opt">=&gt;</span> <span class="hl str">&apos;Firewire&apos;</span><span class="hl opt">,</span>
            sysfs_device <span class="hl opt">=&gt;</span> <span class="hl kwb">$dir,</span>
        <span class="hl opt">};</span>
    <span class="hl opt">}</span> <span class="hl kwc">grep</span> <span class="hl opt">{ -</span>f <span class="hl str">&quot;</span><span class="hl ipl">$dev_dir/$_/specifier_id</span><span class="hl str">&quot;</span> <span class="hl opt">}</span> all<span class="hl opt">(</span><span class="hl kwb">$dev_dir</span><span class="hl opt">);</span>

    <span class="hl kwc">my</span> <span class="hl kwb">$e</span><span class="hl opt">;</span>
    <span class="hl kwa">foreach</span> <span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&apos;/proc/bus/ieee1394/devices&apos;</span><span class="hl opt">)) {</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwd">m!Vendor/Model ID: (.*) \[(\w+)\] / (.*) \[(\w+)\]!</span><span class="hl opt">) {</span>
	    <span class="hl kwc">push</span> <span class="hl kwb">&#64;l, $e</span> <span class="hl opt">= {</span> 
			   vendor <span class="hl opt">=&gt;</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$2</span><span class="hl opt">),</span> id <span class="hl opt">=&gt;</span> <span class="hl kwc">hex</span><span class="hl opt">(</span><span class="hl kwb">$4</span><span class="hl opt">),</span> 
			   description <span class="hl opt">=&gt;</span> <span class="hl kwc">join</span><span class="hl opt">(</span><span class="hl str">&apos;|&apos;</span><span class="hl opt">,</span> <span class="hl kwb">$1, $3</span><span class="hl opt">),</span>
			   bus <span class="hl opt">=&gt;</span> <span class="hl str">&apos;Firewire&apos;</span><span class="hl opt">,</span>
			  <span class="hl opt">};</span>
	<span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwd">/Software Specifier ID: (\w+)/</span><span class="hl opt">) {</span>
	    <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>specifier_id<span class="hl opt">} =</span> <span class="hl kwc">hex</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>
	<span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwd">/Software Version: (\w+)/</span><span class="hl opt">) {</span>
	    <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>specifier_version<span class="hl opt">} =</span> <span class="hl kwc">hex</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>	    
	<span class="hl opt">}</span>
    <span class="hl opt">}</span>

    <span class="hl kwa">foreach</span> <span class="hl opt">(</span><span class="hl kwb">&#64;l</span><span class="hl opt">) {</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>specifier_id<span class="hl opt">} ==</span> <span class="hl num">0x00609e</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>specifier_version<span class="hl opt">} ==</span> <span class="hl num">0x010483</span><span class="hl opt">) {</span>
	    add2hash<span class="hl opt">(</span><span class="hl kwb">$_,</span> <span class="hl opt">{</span> driver <span class="hl opt">=&gt;</span> <span class="hl str">&apos;sbp2&apos;</span><span class="hl opt">,</span> description <span class="hl opt">=&gt;</span> <span class="hl str">&quot;Generic Firewire Storage Controller&quot;</span> <span class="hl opt">});</span>
	<span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>specifier_id<span class="hl opt">} ==</span> <span class="hl num">0x00005e</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>specifier_version<span class="hl opt">} ==</span> <span class="hl num">0x000001</span><span class="hl opt">) {</span>
	    add2hash<span class="hl opt">(</span><span class="hl kwb">$_,</span> <span class="hl opt">{</span> driver <span class="hl opt">=&gt;</span> <span class="hl str">&apos;eth1394&apos;</span><span class="hl opt">,</span> description <span class="hl opt">=&gt;</span> <span class="hl str">&quot;IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)&quot;</span> <span class="hl opt">});</span>
	<span class="hl opt">}</span>
    <span class="hl opt">}</span>
    <span class="hl kwb">&#64;l</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> pcmcia_controller_probe<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$controller</span><span class="hl opt">) =</span>  probe_category<span class="hl opt">(</span><span class="hl str">&apos;bus/pcmcia&apos;</span><span class="hl opt">);</span>
    <span class="hl kwa">if</span> <span class="hl opt">(!</span><span class="hl kwb">$controller</span> <span class="hl opt">&amp;&amp; !$::</span>testing <span class="hl opt">&amp;&amp; !$::</span>noauto <span class="hl opt">&amp;&amp;</span> arch<span class="hl opt">() =~</span> <span class="hl kwd">/i.86/</span><span class="hl opt">) {</span>
        <span class="hl kwc">my</span> <span class="hl kwb">$driver</span> <span class="hl opt">=</span> c<span class="hl opt">::</span>pcmcia_probe<span class="hl opt">();</span>
        <span class="hl kwb">$controller</span> <span class="hl opt">= {</span> driver <span class="hl opt">=&gt;</span> <span class="hl kwb">$driver,</span> description <span class="hl opt">=&gt;</span> <span class="hl str">&quot;PCMCIA controller (</span><span class="hl ipl">$driver</span><span class="hl str">)&quot;</span> <span class="hl opt">}</span> <span class="hl kwa">if</span> <span class="hl kwb">$driver</span><span class="hl opt">;</span>
    <span class="hl opt">}</span>
    <span class="hl kwb">$controller</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> pcmcia_probe<span class="hl opt">() {</span>
    <span class="hl kwa">require</span> modalias<span class="hl opt">;</span>
    <span class="hl kwa">require</span> modules<span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$dev_dir</span> <span class="hl opt">=</span> <span class="hl str">&apos;/sys/bus/pcmcia/devices&apos;</span><span class="hl opt">;</span>
    <span class="hl kwc">map</span> <span class="hl opt">{</span>
        <span class="hl kwc">my</span> <span class="hl kwb">$dir</span> <span class="hl opt">=</span> <span class="hl str">&quot;</span><span class="hl ipl">$dev_dir/$_</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
        <span class="hl kwc">my</span> <span class="hl kwb">$get</span> <span class="hl opt">=</span> <span class="hl kwa">sub</span> <span class="hl opt">{</span> chomp_<span class="hl opt">(</span>cat_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$dir/$_</span><span class="hl str">[0]&quot;</span><span class="hl opt">)) };</span>
        <span class="hl kwc">my</span> <span class="hl kwb">$class_dev</span> <span class="hl opt">=</span> first<span class="hl opt">(</span>glob_<span class="hl opt">(</span><span class="hl str">&quot;</span><span class="hl ipl">$dir/tty*</span><span class="hl str">&quot;</span><span class="hl opt">));</span>
        <span class="hl kwc">my</span> <span class="hl kwb">$device</span> <span class="hl opt">=</span> <span class="hl kwb">$class_dev</span> <span class="hl opt">&amp;&amp;</span> get_sysfs_field_from_link<span class="hl opt">(</span><span class="hl kwb">$dir,</span> basename<span class="hl opt">(</span><span class="hl kwb">$class_dev</span><span class="hl opt">));</span>
        <span class="hl kwc">my</span> <span class="hl kwb">$modalias</span> <span class="hl opt">=</span> <span class="hl kwb">$get</span><span class="hl opt">-&gt;(</span><span class="hl str">&apos;modalias&apos;</span><span class="hl opt">);</span>
        <span class="hl kwc">my</span> <span class="hl kwb">$driver</span> <span class="hl opt">=</span> get_sysfs_field_from_link<span class="hl opt">(</span><span class="hl kwb">$dir,</span> <span class="hl str">&apos;driver&apos;</span><span class="hl opt">);</span>
        <span class="hl slc">#- fallback on modalias result</span>
        <span class="hl slc">#- but only if the module isn&apos;t loaded yet (else, it would already be binded)</span>
        <span class="hl slc">#- this prevents from guessing the wrong driver for multi-function devices</span>
        <span class="hl kwc">my</span> <span class="hl kwb">$module</span> <span class="hl opt">=</span> <span class="hl kwb">$modalias</span> <span class="hl opt">&amp;&amp;</span> first<span class="hl opt">(</span>modalias<span class="hl opt">::</span>get_modules<span class="hl opt">(</span><span class="hl kwb">$modalias</span><span class="hl opt">));</span>
        <span class="hl kwb">$driver</span> <span class="hl opt">||= !</span>member<span class="hl opt">(</span><span class="hl kwb">$module,</span> modules<span class="hl opt">::</span>loaded_modules<span class="hl opt">()) &amp;&amp;</span> <span class="hl kwb">$module</span><span class="hl opt">;</span>
        <span class="hl opt">{</span>
            description <span class="hl opt">=&gt;</span> <span class="hl kwc">join</span><span class="hl opt">(</span><span class="hl str">&apos; &apos;</span><span class="hl opt">,</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span> <span class="hl opt">}</span> <span class="hl kwc">map</span> <span class="hl opt">{</span> <span class="hl kwb">$get</span><span class="hl opt">-&gt;(</span><span class="hl str">&quot;prod_id</span><span class="hl ipl">$_</span><span class="hl str">&quot;</span><span class="hl opt">) }</span> <span class="hl num">1</span> <span class="hl opt">..</span> <span class="hl num">4</span><span class="hl opt">),</span>
            driver <span class="hl opt">=&gt;</span> <span class="hl kwb">$driver,</span>
            if_<span class="hl opt">(</span><span class="hl kwb">$modalias,</span> modalias <span class="hl opt">=&gt;</span> <span class="hl kwb">$modalias</span><span class="hl opt">),</span>
            if_<span class="hl opt">(</span><span class="hl kwb">$device,</span> device <span class="hl opt">=&gt;</span> <span class="hl kwb">$device</span><span class="hl opt">),</span>
            bus <span class="hl opt">=&gt;</span> <span class="hl str">&apos;PCMCIA&apos;</span><span class="hl opt">,</span>
            sysfs_device <span class="hl opt">=&gt;</span> <span class="hl kwb">$dir,</span>
        <span class="hl opt">};</span>
    <span class="hl opt">}</span> all<span class="hl opt">(</span><span class="hl kwb">$dev_dir</span><span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwc">my</span> <span class="hl kwb">$dmi_probe</span><span class="hl opt">;</span>
<span class="hl kwa">sub</span> dmi_probe<span class="hl opt">() {</span>
    <span class="hl kwb">$dmi_probe</span> <span class="hl opt">||= [</span> <span class="hl kwc">map</span> <span class="hl opt">{</span>
	<span class="hl kwd">/(.*?)\t(.*)/</span> <span class="hl opt">&amp;&amp; {</span> bus <span class="hl opt">=&gt;</span> <span class="hl str">&apos;DMI&apos;</span><span class="hl opt">,</span> driver <span class="hl opt">=&gt;</span> <span class="hl kwb">$1,</span> description <span class="hl opt">=&gt;</span> <span class="hl kwb">$2</span> <span class="hl opt">};</span>
    <span class="hl opt">} $&gt;</span> ? <span class="hl opt">() :</span> c<span class="hl opt">::</span>dmi_probe<span class="hl opt">() ];</span>
    <span class="hl kwb">&#64;$dmi_probe</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl slc"># pcmcia_probe provides field &quot;device&quot;, used in network.pm</span>
<span class="hl slc"># =&gt; probeall with $probe_type is unsafe</span>
<span class="hl kwa">sub</span> probeall<span class="hl opt">() {</span>
    <span class="hl kwa">return if</span> <span class="hl opt">$::</span>noauto<span class="hl opt">;</span>

    pci_probe<span class="hl opt">(),</span> usb_probe<span class="hl opt">(),</span> firewire_probe<span class="hl opt">(),</span> pcmcia_probe<span class="hl opt">(),</span> dmi_probe<span class="hl opt">(),</span> getInputDevices_and_usb<span class="hl opt">();</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> probeall_update_cache<span class="hl opt">() {</span>
    <span class="hl kwa">return if</span> <span class="hl opt">$::</span>noauto<span class="hl opt">;</span>
    <span class="hl kwb">&#64;pci</span> <span class="hl opt">=</span> pci_probe__real<span class="hl opt">(),</span> <span class="hl kwb">&#64;usb</span> <span class="hl opt">=</span> usb_probe__real<span class="hl opt">(),</span> firewire_probe<span class="hl opt">(),</span> pcmcia_probe<span class="hl opt">(),</span> dmi_probe<span class="hl opt">();</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> matching_desc__regexp <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$regexp</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>description<span class="hl opt">} =~</span> <span class="hl kwd">/$regexp/i</span> <span class="hl opt">}</span> probeall<span class="hl opt">();</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> matching_driver__regexp <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$regexp</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =~</span> <span class="hl kwd">/$regexp/i</span> <span class="hl opt">}</span> probeall<span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> matching_driver <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">&#64;list</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">grep</span> <span class="hl opt">{</span> member<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">},</span> <span class="hl kwb">&#64;list</span><span class="hl opt">) }</span> probeall<span class="hl opt">();</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> probe_name <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$name</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">map</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =~</span> <span class="hl kwd">/^$name:(.*)/</span> <span class="hl opt">}</span> probeall<span class="hl opt">();</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> probe_unique_name <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$name</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;l</span> <span class="hl opt">=</span> uniq<span class="hl opt">(</span>probe_name<span class="hl opt">(</span><span class="hl kwb">$name</span><span class="hl opt">));</span>
    <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">&#64;l</span> <span class="hl opt">&gt;</span> <span class="hl num">1</span><span class="hl opt">) {</span>
	<span class="hl kwc">log</span><span class="hl opt">::</span>l<span class="hl opt">(</span><span class="hl str">&quot;oops, more than one</span> <span class="hl ipl">$name</span> <span class="hl str">from probe: &quot;</span><span class="hl opt">,</span> <span class="hl kwc">join</span><span class="hl opt">(</span><span class="hl str">&apos; &apos;</span><span class="hl opt">,</span> <span class="hl kwb">&#64;l</span><span class="hl opt">));</span>
    <span class="hl opt">}</span>
    <span class="hl kwb">$l</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">];</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> stringlist <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$b_verbose</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">map</span> <span class="hl opt">{</span>
	<span class="hl kwc">my</span> <span class="hl kwb">$ids</span> <span class="hl opt">=</span> <span class="hl kwb">$b_verbose</span> <span class="hl opt">||</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>description<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;(null)&apos;</span> ?  <span class="hl kwc">sprintf</span><span class="hl opt">(</span><span class="hl str">&quot;vendor:</span><span class="hl ipl">%04x</span> <span class="hl str">device:</span><span class="hl ipl">%04x</span><span class="hl str">&quot;</span><span class="hl opt">,</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>vendor<span class="hl opt">},</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>id<span class="hl opt">}) :</span> <span class="hl str">&apos;&apos;</span><span class="hl opt">;</span>
	<span class="hl kwc">my</span> <span class="hl kwb">$subids</span> <span class="hl opt">=</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>subid<span class="hl opt">} &amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>subid<span class="hl opt">} !=</span> <span class="hl num">0xffff</span> ? <span class="hl kwc">sprintf</span><span class="hl opt">(</span><span class="hl str">&quot;subv:</span><span class="hl ipl">%04x</span> <span class="hl str">subd:</span><span class="hl ipl">%04x</span><span class="hl str">&quot;</span><span class="hl opt">,</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>subvendor<span class="hl opt">},</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>subid<span class="hl opt">}) :</span> <span class="hl str">&apos;&apos;</span><span class="hl opt">;</span>
	<span class="hl kwc">sprintf</span><span class="hl opt">(</span><span class="hl str">&quot;%-16s:</span> <span class="hl ipl">%s%s%s</span><span class="hl str">&quot;</span><span class="hl opt">,</span> 
		<span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} ||</span> <span class="hl str">&apos;unknown&apos;</span><span class="hl opt">,</span> 
		<span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>description<span class="hl opt">},</span>
		<span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">}</span> ? <span class="hl kwc">sprintf</span><span class="hl opt">(</span><span class="hl str">&quot; [</span><span class="hl ipl">%s</span><span class="hl str">]&quot;</span><span class="hl opt">,</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">}) :</span> <span class="hl str">&apos;&apos;</span><span class="hl opt">,</span>
		<span class="hl kwb">$ids</span> <span class="hl opt">||</span> <span class="hl kwb">$subids</span> ? <span class="hl str">&quot; (</span><span class="hl ipl">$ids</span><span class="hl str">&quot;</span> <span class="hl opt">. (</span><span class="hl kwb">$ids</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$subids</span> <span class="hl opt">&amp;&amp;</span> <span class="hl str">&quot; &quot;</span><span class="hl opt">) .</span> <span class="hl str">&quot;</span><span class="hl ipl">$subids</span><span class="hl str">)&quot;</span> <span class="hl opt">:</span> <span class="hl str">&apos;&apos;</span><span class="hl opt">,</span>
	       <span class="hl opt">);</span>
    <span class="hl opt">}</span> probeall<span class="hl opt">();</span> 
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> tryOpen<span class="hl opt">($) {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$F</span><span class="hl opt">;</span>
    <span class="hl kwc">sysopen</span><span class="hl opt">(</span><span class="hl kwb">$F,</span> devices<span class="hl opt">::</span>make<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]),</span> c<span class="hl opt">::</span>O_NONBLOCK<span class="hl opt">()) &amp;&amp;</span> <span class="hl kwb">$F</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> tryWrite<span class="hl opt">($) {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$F</span><span class="hl opt">;</span>
    <span class="hl kwc">sysopen</span><span class="hl opt">(</span><span class="hl kwb">$F,</span> devices<span class="hl opt">::</span>make<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]),</span> <span class="hl num">1</span> <span class="hl opt">|</span> c<span class="hl opt">::</span>O_NONBLOCK<span class="hl opt">()) &amp;&amp;</span> <span class="hl kwb">$F</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwc">my</span> <span class="hl kwb">&#64;dmesg</span><span class="hl opt">;</span>
<span class="hl kwa">sub</span> syslog<span class="hl opt">() {</span>
    <span class="hl kwa">if</span> <span class="hl opt">(-</span>r <span class="hl str">&quot;/tmp/syslog&quot;</span><span class="hl opt">) {</span>
	<span class="hl kwc">map</span> <span class="hl opt">{</span> <span class="hl kwd">/&lt;\d+&gt;(.*)/</span> <span class="hl opt">}</span> cat_<span class="hl opt">(</span><span class="hl str">&quot;/tmp/syslog&quot;</span><span class="hl opt">);</span>
    <span class="hl opt">}</span> <span class="hl kwa">else</span> <span class="hl opt">{</span>
	<span class="hl kwb">&#64;dmesg</span> <span class="hl opt">=</span> <span class="hl str">`/bin/dmesg`</span> <span class="hl kwa">if</span> <span class="hl opt">!</span><span class="hl kwb">&#64;dmesg</span><span class="hl opt">;</span>
	<span class="hl kwb">&#64;dmesg</span><span class="hl opt">;</span>
    <span class="hl opt">}</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_mac_model<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$mac_model</span> <span class="hl opt">=</span> cat_<span class="hl opt">(</span><span class="hl str">&quot;/proc/device-tree/model&quot;</span><span class="hl opt">) ||</span> <span class="hl kwc">die</span> <span class="hl str">&quot;Can not open /proc/device-tree/model&quot;</span><span class="hl opt">;</span>
    <span class="hl kwc">log</span><span class="hl opt">::</span>l<span class="hl opt">(</span><span class="hl str">&quot;Mac model:</span> <span class="hl ipl">$mac_model</span><span class="hl str">&quot;</span><span class="hl opt">);</span>
    <span class="hl kwb">$mac_model</span><span class="hl opt">;</span>	
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> get_mac_generation<span class="hl opt">() {</span>
    cat_<span class="hl opt">(</span><span class="hl str">&apos;/proc/cpuinfo&apos;</span><span class="hl opt">) =~</span> <span class="hl kwd">/^pmac-generation\s*:\s*(.*)/m</span> ? <span class="hl kwb">$1</span> <span class="hl opt">:</span> <span class="hl str">&quot;Unknown Generation&quot;</span><span class="hl opt">;</span>	
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> hasSMP<span class="hl opt">() {</span> 
    <span class="hl kwa">return if</span> <span class="hl opt">$::</span>testing<span class="hl opt">;</span>
    <span class="hl opt">(</span>any <span class="hl opt">{</span> <span class="hl kwd">/NR_CPUS limit of 1 reached/</span> <span class="hl opt">}</span> syslog<span class="hl opt">()) ||</span>
     <span class="hl opt">(</span>any <span class="hl opt">{</span> <span class="hl kwd">/^processor\s*:\s*(\d+)/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span> <span class="hl opt">&gt;</span> <span class="hl num">0</span> <span class="hl opt">}</span> cat_<span class="hl opt">(</span><span class="hl str">&apos;/proc/cpuinfo&apos;</span><span class="hl opt">)) ||</span>
      any <span class="hl opt">{</span> <span class="hl kwd">/\bProcessor #(\d+)\s+(\S*)/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span> <span class="hl opt">&gt;</span> <span class="hl num">0</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$2</span> <span class="hl kwc">ne</span> <span class="hl str">&apos;invalid&apos;</span> <span class="hl opt">}</span> syslog<span class="hl opt">();</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> hasPCMCIA<span class="hl opt">() { $::</span>o-<span class="hl opt">&gt;{</span>pcmcia<span class="hl opt">} }</span> <span class="hl slc">#- because /proc/pcmcia seems not to be present on 2.4 at least (or use /var/run/stab)</span>

<span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">&#64;dmis, $dmidecode_already_runned</span><span class="hl opt">);</span>

<span class="hl slc"># we return a list b/c several DMIs have the same name:</span>
<span class="hl kwa">sub</span> dmidecode<span class="hl opt">() {</span>
    <span class="hl kwa">return</span> <span class="hl kwb">&#64;dmis</span> <span class="hl kwa">if</span> <span class="hl kwb">$dmidecode_already_runned</span><span class="hl opt">;</span>

    <span class="hl kwa">return if</span> <span class="hl opt">$&gt;;</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$ver, &#64;l</span><span class="hl opt">) =</span> run_program<span class="hl opt">::</span>get_stdout<span class="hl opt">(</span><span class="hl str">&apos;dmidecode&apos;</span><span class="hl opt">);</span>

    <span class="hl kwc">my</span> <span class="hl kwb">$tab</span> <span class="hl opt">=</span> <span class="hl str">&quot;</span><span class="hl esc">\t</span><span class="hl str">&quot;</span><span class="hl opt">;</span>

    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$major, $minor</span><span class="hl opt">) =</span> <span class="hl kwb">$ver</span> <span class="hl opt">=~</span> <span class="hl kwd">/(\d+)\.(\d+)/</span><span class="hl opt">;</span>

    <span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwb">$major</span> <span class="hl opt">&gt;</span> <span class="hl num">2</span> <span class="hl opt">||</span> <span class="hl kwb">$major</span> <span class="hl opt">==</span> <span class="hl num">2</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$minor</span> <span class="hl opt">&gt;</span><span class="hl num">7</span><span class="hl opt">) {</span>
	<span class="hl slc">#- new dmidecode output is less indented</span>
	<span class="hl kwb">$tab</span> <span class="hl opt">=</span> <span class="hl str">&apos;&apos;</span><span class="hl opt">;</span>
	<span class="hl slc">#- drop header</span>
	<span class="hl kwc">shift</span> <span class="hl kwb">&#64;l</span> <span class="hl kwa">while</span> <span class="hl kwb">&#64;l</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$l</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">]</span> <span class="hl kwc">ne</span> <span class="hl str">&quot;</span><span class="hl esc">\n</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
    <span class="hl opt">}</span>

    <span class="hl kwa">foreach</span> <span class="hl opt">(</span><span class="hl kwb">&#64;l</span><span class="hl opt">) {</span>
	<span class="hl kwa">if</span> <span class="hl opt">(</span><span class="hl kwd">/^$tab\t(.*)/</span><span class="hl opt">) {</span>
	    <span class="hl kwb">$dmis</span><span class="hl opt">[-</span><span class="hl num">1</span><span class="hl opt">]{</span>string<span class="hl opt">} .=</span> <span class="hl str">&quot;</span><span class="hl ipl">$1\n</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
	    <span class="hl kwb">$dmis</span><span class="hl opt">[-</span><span class="hl num">1</span><span class="hl opt">]{</span><span class="hl kwb">$1</span><span class="hl opt">} =</span> <span class="hl kwb">$2</span> <span class="hl kwa">if</span> <span class="hl kwd">/^$tab\t(.*): (.*)$/</span><span class="hl opt">;</span>
	<span class="hl opt">}</span> <span class="hl kwa">elsif</span> <span class="hl opt">(</span><span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$s</span><span class="hl opt">) =</span> <span class="hl kwd">/^$tab(.*)/</span><span class="hl opt">) {</span>
	    <span class="hl kwa">next if</span> <span class="hl kwb">$s</span> <span class="hl opt">=~</span> <span class="hl kwd">/^$/</span> <span class="hl opt">||</span> <span class="hl kwb">$s</span> <span class="hl opt">=~</span> <span class="hl kwd">/\bDMI type \d+/</span><span class="hl opt">;</span>
	    <span class="hl kwb">$s</span> <span class="hl opt">=~</span> <span class="hl kwd">s/ Information$//</span><span class="hl opt">;</span>
	    <span class="hl kwc">push</span> <span class="hl kwb">&#64;dmis,</span> <span class="hl opt">{</span> name <span class="hl opt">=&gt;</span> <span class="hl kwb">$s</span> <span class="hl opt">};</span>
	<span class="hl opt">}</span>
    <span class="hl opt">}</span>
    <span class="hl kwb">$dmidecode_already_runned</span> <span class="hl opt">=</span> <span class="hl num">1</span><span class="hl opt">;</span>
    <span class="hl kwb">&#64;dmis</span><span class="hl opt">;</span>
<span class="hl opt">}</span>
<span class="hl kwa">sub</span> dmidecode_category <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$cat</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;l</span> <span class="hl opt">=</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>name<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl kwb">$cat</span> <span class="hl opt">}</span> dmidecode<span class="hl opt">();</span>
    <span class="hl kwc">wantarray</span><span class="hl opt">()</span> ? <span class="hl kwb">&#64;l</span> <span class="hl opt">:</span> <span class="hl kwb">$l</span><span class="hl opt">[</span><span class="hl num">0</span><span class="hl opt">] || {};</span>
<span class="hl opt">}</span>

<span class="hl slc">#- size in MB</span>
<span class="hl kwa">sub</span> dmi_detect_memory<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;l1</span> <span class="hl opt">=</span> <span class="hl kwc">map</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span><span class="hl str">&apos;Enabled Size&apos;</span><span class="hl opt">} =~</span> <span class="hl kwd">/(\d+) MB/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span> <span class="hl opt">}</span> dmidecode_category<span class="hl opt">(</span><span class="hl str">&apos;Memory Module&apos;</span><span class="hl opt">);</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;l2</span> <span class="hl opt">=</span> <span class="hl kwc">map</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span><span class="hl str">&apos;Form Factor&apos;</span><span class="hl opt">} =~</span> <span class="hl kwd">/^(SIMM|SIP|DIP|DIMM|FB-DIMM|RIMM|SODIMM|SRIMM)$/</span> <span class="hl opt">&amp;&amp;</span> 		     
		     <span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>Size<span class="hl opt">} =~</span> <span class="hl kwd">/(\d+) MB/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span> <span class="hl opt">||</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>Size<span class="hl opt">} =~</span> <span class="hl kwd">/(\d+) kB/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span> <span class="hl opt">*</span> <span class="hl num">1024</span><span class="hl opt">);</span>
		 <span class="hl opt">}</span> dmidecode_category<span class="hl opt">(</span><span class="hl str">&apos;Memory Device&apos;</span><span class="hl opt">);</span>
    max<span class="hl opt">(</span>sum<span class="hl opt">(</span><span class="hl kwb">&#64;l1</span><span class="hl opt">),</span> sum<span class="hl opt">(</span><span class="hl kwb">&#64;l2</span><span class="hl opt">));</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> computer_info<span class="hl opt">() {</span>
     <span class="hl kwc">my</span> <span class="hl kwb">$Chassis</span> <span class="hl opt">=</span> dmidecode_category<span class="hl opt">(</span><span class="hl str">&apos;Chassis&apos;</span><span class="hl opt">)-&gt;{</span>Type<span class="hl opt">} =~</span> <span class="hl kwd">/(\S+)/</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span><span class="hl opt">;</span>

     <span class="hl kwc">my</span> <span class="hl kwb">$date</span> <span class="hl opt">=</span> dmidecode_category<span class="hl opt">(</span><span class="hl str">&apos;BIOS&apos;</span><span class="hl opt">)-&gt;{</span><span class="hl str">&apos;Release Date&apos;</span><span class="hl opt">} ||</span> <span class="hl str">&apos;&apos;</span><span class="hl opt">;</span>
     <span class="hl kwc">my</span> <span class="hl kwb">$BIOS_Year</span> <span class="hl opt">=</span> <span class="hl kwb">$date</span> <span class="hl opt">=~</span> <span class="hl kwd">m!(\d{4})!</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span> <span class="hl opt">||</span>
	             <span class="hl kwb">$date</span> <span class="hl opt">=~</span> <span class="hl kwd">m!\d\d/\d\d/(\d\d)!</span> <span class="hl opt">&amp;&amp;</span> <span class="hl str">&quot;20</span><span class="hl ipl">$1</span><span class="hl str">&quot;</span><span class="hl opt">;</span>
	
     <span class="hl opt">+{</span> 
	 isLaptop <span class="hl opt">=&gt;</span> member<span class="hl opt">(</span><span class="hl kwb">$Chassis,</span> <span class="hl str">&apos;Portable&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;Laptop&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;Notebook&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;Hand Held&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;Sub Notebook&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;Docking Station&apos;</span><span class="hl opt">),</span>
	 isServer <span class="hl opt">=&gt;</span> member<span class="hl opt">(</span><span class="hl kwb">$Chassis,</span> <span class="hl str">&apos;Pizza Box&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;Main Server Chassis&apos;</span><span class="hl opt">,</span> <span class="hl str">&apos;Blade&apos;</span><span class="hl opt">),</span>
	 if_<span class="hl opt">(</span><span class="hl kwb">$BIOS_Year,</span> BIOS_Year <span class="hl opt">=&gt;</span> <span class="hl kwb">$BIOS_Year</span><span class="hl opt">),</span>
     <span class="hl opt">};</span>
<span class="hl opt">}</span>

<span class="hl slc">#- try to detect a laptop, we assume pcmcia service is an indication of a laptop or</span>
<span class="hl slc">#- the following regexp to match graphics card apparently only used for such systems.</span>
<span class="hl kwa">sub</span> isLaptop<span class="hl opt">() {</span>
    arch<span class="hl opt">() =~</span> <span class="hl kwd">/ppc/</span> ? 
      get_mac_model<span class="hl opt">() =~</span> <span class="hl kwd">/Book/</span> <span class="hl opt">:</span>
      computer_info<span class="hl opt">()-&gt;{</span>isLaptop<span class="hl opt">}</span>
	<span class="hl opt">||</span> glob_<span class="hl opt">(</span><span class="hl str">&quot;/sys/bus/acpi/devices/PNP0C0D:*&quot;</span><span class="hl opt">)</span> <span class="hl slc">#- ACPI lid button</span>
	<span class="hl opt">|| (</span>matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;C&amp;T.*655[45]\d&apos;</span><span class="hl opt">) ||</span> matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;C&amp;T.*68554&apos;</span><span class="hl opt">) ||</span>
	    matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;Neomagic.*Magic(Media|Graph)&apos;</span><span class="hl opt">) ||</span>
	    matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;ViRGE.MX&apos;</span><span class="hl opt">) ||</span> matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;S3.*Savage.*[IM]X&apos;</span><span class="hl opt">) ||</span>
	    matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;Intel Corporation\|Mobile&apos;</span><span class="hl opt">) ||</span>
	    matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;</span><span class="hl esc">\b</span><span class="hl str">ATI</span><span class="hl esc">\b</span><span class="hl str">.*(Mobility|</span><span class="hl esc">\b</span><span class="hl str">LT</span><span class="hl esc">\b</span><span class="hl str">)&apos;</span><span class="hl opt">))</span>
	<span class="hl opt">|| (</span>any <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span><span class="hl str">&apos;model name&apos;</span><span class="hl opt">} =~</span> <span class="hl kwd">/\b(mobile|C7-M)\b/i</span> <span class="hl opt">}</span> getCPUs<span class="hl opt">())</span>
	<span class="hl opt">||</span> probe_unique_name<span class="hl opt">(</span><span class="hl str">&quot;Type&quot;</span><span class="hl opt">)</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;laptop&apos;</span>
        <span class="hl slc">#- ipw2100/2200/3945 are Mini-PCI (Express) adapters</span>
	<span class="hl opt">|| (</span>any <span class="hl opt">{</span> member<span class="hl opt">(</span><span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">},</span> <span class="hl str">qw(ipw2100 ipw2200 ipw3945)</span><span class="hl opt">) }</span> pci_probe<span class="hl opt">());</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> isServer<span class="hl opt">() {</span>
    computer_info<span class="hl opt">()-&gt;{</span>isServer<span class="hl opt">}</span>
      <span class="hl opt">|| (</span>any <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>Type<span class="hl opt">} =~</span> <span class="hl kwd">/ECC/</span> <span class="hl opt">}</span> dmidecode_category<span class="hl opt">(</span><span class="hl str">&apos;Memory Module&apos;</span><span class="hl opt">))</span>
      <span class="hl opt">||</span> dmidecode_category<span class="hl opt">(</span><span class="hl str">&apos;System Information&apos;</span><span class="hl opt">)-&gt;{</span>Manufacturer<span class="hl opt">} =~</span> <span class="hl kwd">/Supermicro/i</span>
      <span class="hl opt">||</span> dmidecode_category<span class="hl opt">(</span><span class="hl str">&apos;System Information&apos;</span><span class="hl opt">)-&gt;{</span><span class="hl str">&apos;Product Name&apos;</span><span class="hl opt">} =~</span> <span class="hl kwd">/NetServer|Proliant|PowerEdge|eServer|IBM System x/i</span>
      <span class="hl opt">||</span> matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;LSI Logic.*SCSI&apos;</span><span class="hl opt">)</span>
      <span class="hl opt">||</span> matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;MegaRAID&apos;</span><span class="hl opt">)</span>
      <span class="hl opt">||</span> matching_desc__regexp<span class="hl opt">(</span><span class="hl str">&apos;NetServer&apos;</span><span class="hl opt">)</span>
      <span class="hl opt">|| (</span>any <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span><span class="hl str">&apos;model name&apos;</span><span class="hl opt">} =~</span> <span class="hl kwd">/(Xeon|Opteron)/i</span> <span class="hl opt">}</span> getCPUs<span class="hl opt">());</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> BIGMEM<span class="hl opt">() {</span>
    arch<span class="hl opt">() !~</span> <span class="hl kwd">/x86_64|ia64/</span> <span class="hl opt">&amp;&amp; $&gt; ==</span> <span class="hl num">0</span> <span class="hl opt">&amp;&amp;</span> dmi_detect_memory<span class="hl opt">() &gt;</span> <span class="hl num">4</span> <span class="hl opt">*</span> <span class="hl num">1024</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> is_i586<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">$cpuinfo</span> <span class="hl opt">=</span> cat_<span class="hl opt">(</span><span class="hl str">&apos;/proc/cpuinfo&apos;</span><span class="hl opt">);</span>
    <span class="hl kwb">$cpuinfo</span> <span class="hl opt">=~</span> <span class="hl kwd">/^cpu family\s*:\s*(\d+)/m</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$1</span> <span class="hl opt">&lt;</span> <span class="hl num">6</span> <span class="hl opt">||</span>
      <span class="hl kwb">$cpuinfo</span> <span class="hl opt">=~</span> <span class="hl kwd">/^model name\s*:\s*Transmeta.* TM5800/m</span> <span class="hl opt">||</span> <span class="hl slc"># mdvbz#37866</span>
      <span class="hl opt">!</span>has_cpu_flag<span class="hl opt">(</span><span class="hl str">&apos;cmov&apos;</span><span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> is_xbox<span class="hl opt">() {</span>
    any <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>vendor<span class="hl opt">} ==</span> <span class="hl num">0x10de</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>id<span class="hl opt">} ==</span> <span class="hl num">0x02a5</span> <span class="hl opt">}</span> pci_probe<span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> is_virtualbox<span class="hl opt">() {</span>
    any <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;vboxadd&apos;</span> <span class="hl opt">}</span> detect_devices<span class="hl opt">::</span>pci_probe<span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> is_vmware<span class="hl opt">() {</span>
    any <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =~</span> <span class="hl kwd">/Card:VMware/</span> <span class="hl opt">}</span> detect_devices<span class="hl opt">::</span>pci_probe<span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> is_netbook_nettop<span class="hl opt">() {</span>
    <span class="hl kwc">my</span> <span class="hl kwb">&#64;cpus</span> <span class="hl opt">=</span> getCPUs<span class="hl opt">();</span>
    <span class="hl opt">(</span>any <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span><span class="hl str">&apos;model name&apos;</span><span class="hl opt">} =~</span> <span class="hl kwd">/(\bIntel\(R\) Atom\(TM\)\B)/i</span> <span class="hl opt">}</span> <span class="hl kwb">&#64;cpus</span><span class="hl opt">) ||</span>
    <span class="hl opt">(</span>any <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span><span class="hl str">&apos;model name&apos;</span><span class="hl opt">} =~</span> <span class="hl kwd">/(\bIntel\(R\) Celeron\(R\) M processor\b|\bVIA C7-M Processor\b|\bGeode\(TM\)\B)/i</span> <span class="hl opt">&amp;&amp;</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span><span class="hl str">&apos;cpu MHz&apos;</span><span class="hl opt">} &lt;</span> <span class="hl num">1500</span> <span class="hl opt">}</span> <span class="hl kwb">&#64;cpus</span><span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> has_low_resources<span class="hl opt">() {</span>
    availableRamMB<span class="hl opt">() &lt;</span> <span class="hl num">100</span> <span class="hl opt">||</span> arch<span class="hl opt">() =~</span> <span class="hl kwd">/i.86/</span> <span class="hl opt">&amp;&amp;</span> ix86_cpu_frequency<span class="hl opt">() &lt;</span> <span class="hl num">350</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> need_light_desktop<span class="hl opt">() {</span>
    has_low_resources<span class="hl opt">() ||</span> is_netbook_nettop<span class="hl opt">();</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> has_cpu_flag <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$flag</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    cat_<span class="hl opt">(</span><span class="hl str">&apos;/proc/cpuinfo&apos;</span><span class="hl opt">) =~</span> <span class="hl kwd">/^flags.*\b$flag\b/m</span><span class="hl opt">;</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> matching_types<span class="hl opt">() {</span>
    <span class="hl opt">+{</span>
	laptop <span class="hl opt">=&gt;</span> isLaptop<span class="hl opt">(),</span>
	<span class="hl str">&apos;touchpad&apos;</span> <span class="hl opt">=&gt;</span> hasTouchpad<span class="hl opt">(),</span>
	<span class="hl str">&apos;64bit&apos;</span> <span class="hl opt">=&gt;</span> to_bool<span class="hl opt">(</span>arch<span class="hl opt">() =~</span> <span class="hl kwd">/64/</span><span class="hl opt">),</span>
	wireless <span class="hl opt">=&gt;</span> to_bool<span class="hl opt">(</span>get_wireless_interface<span class="hl opt">() ||</span> probe_category<span class="hl opt">(</span><span class="hl str">&apos;network/wireless&apos;</span><span class="hl opt">)),</span>
    <span class="hl opt">};</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> hasWacom<span class="hl opt">()     {</span> find <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>vendor<span class="hl opt">} ==</span> <span class="hl num">0x056a</span> <span class="hl opt">||</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>driver<span class="hl opt">} =~</span> <span class="hl kwd">/wacom/</span> <span class="hl opt">}</span> usb_probe<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> hasTouchpad<span class="hl opt">()  {</span> any <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>Synaptics<span class="hl opt">} ||</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>ALPS<span class="hl opt">} ||</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>Elantech<span class="hl opt">} }</span> getInputDevices<span class="hl opt">() };</span>

<span class="hl kwa">sub</span> usbWacom<span class="hl opt">()     {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>vendor<span class="hl opt">}</span> <span class="hl kwc">eq</span> <span class="hl str">&apos;056a&apos;</span> <span class="hl opt">}</span> getInputDevices<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> usbKeyboards<span class="hl opt">() {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">} =~</span> <span class="hl kwd">/\|Keyboard/</span> <span class="hl opt">}</span> usb_probe<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> usbStorage<span class="hl opt">()   {</span> <span class="hl kwc">grep</span> <span class="hl opt">{</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>media_type<span class="hl opt">} =~</span> <span class="hl kwd">/Mass Storage\|/</span> <span class="hl opt">}</span> usb_probe<span class="hl opt">() }</span>
<span class="hl kwa">sub</span> has_mesh<span class="hl opt">()     {</span> find <span class="hl opt">{</span> <span class="hl kwd">/mesh/</span> <span class="hl opt">}</span> all_files_rec<span class="hl opt">(</span><span class="hl str">&quot;/proc/device-tree&quot;</span><span class="hl opt">) }</span>
<span class="hl kwa">sub</span> has_53c94<span class="hl opt">()    {</span> find <span class="hl opt">{</span> <span class="hl kwd">/53c94/</span> <span class="hl opt">}</span> all_files_rec<span class="hl opt">(</span><span class="hl str">&quot;/proc/device-tree&quot;</span><span class="hl opt">) }</span>

<span class="hl kwa">sub</span> usbKeyboard2country_code <span class="hl opt">{</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$usb_kbd</span><span class="hl opt">) =</span> <span class="hl kwb">&#64;_</span><span class="hl opt">;</span>
    <span class="hl kwc">my</span> <span class="hl opt">(</span><span class="hl kwb">$F, $tmp</span><span class="hl opt">);</span>
    <span class="hl kwc">sysopen</span><span class="hl opt">(</span><span class="hl kwb">$F,</span> <span class="hl kwc">sprintf</span><span class="hl opt">(</span><span class="hl str">&quot;/proc/bus/usb/</span><span class="hl ipl">%03d/%03d</span><span class="hl str">&quot;</span><span class="hl opt">,</span> <span class="hl kwb">$usb_kbd</span><span class="hl opt">-&gt;{</span>pci_bus<span class="hl opt">},</span> <span class="hl kwb">$usb_kbd</span><span class="hl opt">-&gt;{</span>pci_device<span class="hl opt">}),</span> <span class="hl num">0</span><span class="hl opt">)</span> <span class="hl kwc">and</span>
      <span class="hl kwc">sysseek</span> <span class="hl kwb">$F,</span> <span class="hl num">0x28</span><span class="hl opt">,</span> <span class="hl num">0</span> <span class="hl kwc">and</span>
      <span class="hl kwc">sysread</span> <span class="hl kwb">$F, $tmp,</span> <span class="hl num">1</span> <span class="hl kwc">and</span>
      <span class="hl kwc">unpack</span><span class="hl opt">(</span><span class="hl str">&quot;C&quot;</span><span class="hl opt">,</span> <span class="hl kwb">$tmp</span><span class="hl opt">);</span>
<span class="hl opt">}</span>

<span class="hl kwa">sub</span> probeSerialDevices<span class="hl opt">() {</span>
    <span class="hl kwa">require</span> list_modules<span class="hl opt">;</span>
    <span class="hl kwa">require</span> modules<span class="hl opt">;</span>
    modules<span class="hl opt">::</span>append_to_modules_loaded_at_startup_for_all_kernels<span class="hl opt">(</span>modules<span class="hl opt">::</span>load_category<span class="hl opt">($::</span>o-<span class="hl opt">&gt;{</span>modules_conf<span class="hl opt">},</span> <span class="hl str">&apos;various/serial&apos;</span><span class="hl opt">));</span>
    <span class="hl kwa">foreach</span> <span class="hl opt">(</span><span class="hl num">0</span><span class="hl opt">.</span><span class="hl num">.3</span><span class="hl opt">) {</span>
	<span class="hl slc">#- make sure the device are created before probing,</span>
	devices<span class="hl opt">::</span>make<span class="hl opt">(</span><span class="hl str">&quot;/dev/ttyS</span><span class="hl ipl">$_</span><span class="hl str">&quot;</span><span class="hl opt">);</span>
	<span class="hl slc">#- and make sure the device is a real terminal (major is 4).</span>
	<span class="hl kwc">int</span><span class="hl opt">((</span><span class="hl kwc">stat</span> <span class="hl str">&quot;/dev/ttyS</span><span class="hl ipl">$_</span><span class="hl str">&quot;</span><span class="hl opt">)[</span><span class="hl num">6</span><span class="hl opt">]</span><span class="hl kwd">/256) == 4 or $serialprobe{&quot;/d</span>ev<span class="hl opt">/</span>ttyS<span class="hl kwb">$_</span><span class="hl str">&quot;} = undef;</span>
<span class="hl str">    }</span>
<span class="hl str"></span>
<span class="hl str">    #- for device already probed, we can safely (assuming device are</span>
<span class="hl str">    #- not moved during install :-)</span>
<span class="hl str">    #- include /dev/mouse device if using an X server.</span>
<span class="hl str">    mkdir_p(&quot;</span><span class="hl kwd">/var/loc</span>k<span class="hl str">&quot;);</span>
<span class="hl str">    -l &quot;</span><span class="hl kwd">/dev/mous</span>e<span class="hl str">&quot; and</span> <span class="hl ipl">$serialprobe</span><span class="hl str">{&quot;</span><span class="hl kwd">/dev/</span><span class="hl str">&quot; . readlink &quot;</span><span class="hl kwd">/dev/mous</span>e<span class="hl str">&quot;} = undef;</span>
<span class="hl str">    foreach (keys</span> <span class="hl ipl">%serialprobe</span><span class="hl str">) { m|^/dev/(.*)| and touch &quot;</span><span class="hl kwd">/var/loc</span>k<span class="hl opt">/</span>LCK<span class="hl opt">..</span><span class="hl kwb">$1</span><span class="hl str">&quot; }</span>
<span class="hl str"></span>
<span class="hl str">    print STDERR &quot;</span>Please <span class="hl kwc">wait</span> <span class="hl kwa">while</span> probing serial ports<span class="hl opt">...</span><span class="hl esc">\n</span><span class="hl str">&quot;;</span>
<span class="hl str">    #- start probing all serial ports... really faster than before ...</span>
<span class="hl str">    #- ... but still take some time :-)</span>
<span class="hl str">    my</span> <span class="hl ipl">%current</span><span class="hl str">; </span>
<span class="hl str">    foreach (run_program::get_stdout(&apos;serial_probe&apos;)) {</span>
<span class="hl str">	if (/^\s*</span><span class="hl ipl">$/</span><span class="hl str">) {</span>
<span class="hl str"></span>	    <span class="hl ipl">$serialprobe</span><span class="hl str">{</span><span class="hl ipl">$current</span><span class="hl str">{DEVICE}} = {</span> <span class="hl ipl">%current</span> <span class="hl str">} if</span> <span class="hl ipl">$current</span><span class="hl str">{DEVICE};</span>
<span class="hl str"></span>	    <span class="hl ipl">%current</span> <span class="hl str">= ();</span>
<span class="hl str">	} elsif (/^([^=]+)=(.*?)\s*</span><span class="hl ipl">$/</span><span class="hl str">) {</span>
<span class="hl str"></span>	    <span class="hl ipl">$current</span><span class="hl str">{</span><span class="hl ipl">$1</span><span class="hl str">} =</span> <span class="hl ipl">$2</span><span class="hl str">;</span>
<span class="hl str">	}</span>
<span class="hl str">    }</span>
<span class="hl str"></span>
<span class="hl str">    foreach (values</span> <span class="hl ipl">%serialprobe</span><span class="hl str">) {</span>
<span class="hl str"></span>	<span class="hl ipl">$_</span><span class="hl str">-&gt;{DESCRIPTION} =~ /modem/i and</span> <span class="hl ipl">$_</span><span class="hl str">-&gt;{CLASS} = &apos;MODEM&apos;; #- hack to make sure a modem is detected.</span>
<span class="hl str"></span>	<span class="hl ipl">$_</span><span class="hl str">-&gt;{DESCRIPTION} =~ /olitec/i and</span> <span class="hl ipl">$_</span><span class="hl str">-&gt;{CLASS} = &apos;MODEM&apos;; #- hack to make sure such modem gets detected.</span>
<span class="hl str">	log::l(&quot;</span>probed <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>DESCRIPTION<span class="hl opt">}</span> of <span class="hl kwa">class</span> <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>CLASS<span class="hl opt">}</span> on device <span class="hl kwb">$_</span><span class="hl opt">-&gt;{</span>DEVICE<span class="hl opt">}</span><span class="hl str">&quot;);</span>
<span class="hl str">    }</span>
<span class="hl str">}</span>
<span class="hl str"></span>
<span class="hl str">sub probeSerial($) {</span> <span class="hl ipl">$serialprobe</span><span class="hl str">{</span><span class="hl ipl">$_</span><span class="hl str">[0]} }</span>
<span class="hl str"></span>
<span class="hl str">sub hasModem($) {</span>
<span class="hl str"></span>    <span class="hl ipl">$serialprobe</span><span class="hl str">{</span><span class="hl ipl">$_</span><span class="hl str">[0]} &amp;&amp;</span> <span class="hl ipl">$serialprobe</span><span class="hl str">{</span><span class="hl ipl">$_</span><span class="hl str">[0]}{CLASS} eq &apos;MODEM&apos; &amp;&amp;</span> <span class="hl ipl">$serialprobe</span><span class="hl str">{</span><span class="hl ipl">$_</span><span class="hl str">[0]}{DESCRIPTION};</span>
<span class="hl str">}</span>
<span class="hl str"></span>
<span class="hl str">sub hasMousePS2 {</span>
<span class="hl str">    my</span> <span class="hl ipl">$t</span><span class="hl str">; sysread(tryOpen(</span><span class="hl ipl">$_</span><span class="hl str">[0]) || return,</span> <span class="hl ipl">$t,</span> <span class="hl str">256) != 1 ||</span> <span class="hl ipl">$t</span> <span class="hl str">ne &quot;</span><span class="hl esc">\xFE</span><span class="hl str">&quot;;</span>
<span class="hl str">}</span>
<span class="hl str"></span>
<span class="hl str">sub probeall_unavailable_modules {</span>
<span class="hl str">    map {</span>
<span class="hl str">        my</span> <span class="hl ipl">$driver</span> <span class="hl str">=</span> <span class="hl ipl">$_</span><span class="hl str">-&gt;{driver};</span>
<span class="hl str"></span>        <span class="hl ipl">$driver</span> <span class="hl str">!~ /:/ &amp;&amp;</span>
<span class="hl str">        !member(</span><span class="hl ipl">$driver,</span> <span class="hl str">&apos;hub&apos;, &apos;unknown&apos;, &apos;amd64_agp&apos;) &amp;&amp;</span>
<span class="hl str">        !modules::module_is_available(</span><span class="hl ipl">$driver</span><span class="hl str">) ?</span>
<span class="hl str"></span>          <span class="hl ipl">$driver</span> <span class="hl str">:</span>
<span class="hl str">          ();</span>
<span class="hl str">    } probeall();</span>
<span class="hl str">}</span>
<span class="hl str"></span>
<span class="hl str">sub probeall_dkms_modules {</span>
<span class="hl str">    my</span> <span class="hl ipl">&#64;unavailable_modules</span> <span class="hl str">= probeall_unavailable_modules() or return;</span>
<span class="hl str">    require modalias;</span>
<span class="hl str">    my</span> <span class="hl ipl">$dkms_modules</span> <span class="hl str">= modalias::parse_file_modules($::prefix . &quot;</span><span class="hl kwd">/usr/s</span>hare<span class="hl kwd">/ldetect-lst/d</span>kms<span class="hl opt">-</span>modules<span class="hl opt">.</span>alias<span class="hl str">&quot;);</span>
<span class="hl str">    intersection([ keys(</span><span class="hl ipl">%$dkms_modules</span><span class="hl str">) ], \</span><span class="hl ipl">&#64;unavailable_modules</span><span class="hl str">);</span>
<span class="hl str">}</span>
<span class="hl str"></span>
<span class="hl str">sub usb_description2removable {</span>
<span class="hl str">    local (</span><span class="hl ipl">$_</span><span class="hl str">) =</span> <span class="hl ipl">&#64;_</span><span class="hl str">;</span>
<span class="hl str">    return &apos;camera&apos; if /</span><span class="hl esc">\b</span><span class="hl str">camera</span><span class="hl esc">\b</span><span class="hl str">/i;</span>
<span class="hl str">    return &apos;memory_card&apos; if /</span><span class="hl esc">\b</span><span class="hl str">memory\s?stick</span><span class="hl esc">\b</span><span class="hl str">/i || /</span><span class="hl esc">\b</span><span class="hl str">compact\s?flash</span><span class="hl esc">\b</span><span class="hl str">/i || /</span><span class="hl esc">\b</span><span class="hl str">smart\s?media</span><span class="hl esc">\b</span><span class="hl str">/i;</span>
<span class="hl str">    return &apos;memory_card&apos; if /DiskOnKey/i || /IBM-DMDM/i;</span>
<span class="hl str">    return &apos;zip&apos; if /</span><span class="hl esc">\b</span><span class="hl str">zip\s?(100|250|750)/i;</span>
<span class="hl str">    return &apos;floppy&apos; if /</span><span class="hl esc">\b</span><span class="hl str">LS-?120</span><span class="hl esc">\b</span><span class="hl str">/i;</span>
<span class="hl str">    return;</span>
<span class="hl str">}</span>
<span class="hl str"></span>
<span class="hl str">sub usb2removable {</span>
<span class="hl str">    my (</span><span class="hl ipl">$e</span><span class="hl str">) =</span> <span class="hl ipl">&#64;_</span><span class="hl str">;</span>
<span class="hl str"></span>    <span class="hl ipl">$e</span><span class="hl str">-&gt;{usb_driver} or return;</span>
<span class="hl str"></span>
<span class="hl str">    if (</span><span class="hl ipl">$e</span><span class="hl str">-&gt;{usb_driver} =~ /Removable:(.*)/) {</span>
<span class="hl str">	return</span> <span class="hl ipl">$1</span><span class="hl str">;</span>
<span class="hl str">    } elsif (my</span> <span class="hl ipl">$name</span> <span class="hl str">= usb_description2removable(</span><span class="hl ipl">$e</span><span class="hl str">-&gt;{usb_description})) {</span>
<span class="hl str">	return</span> <span class="hl ipl">$name</span><span class="hl str">;</span>
<span class="hl str">    }</span>
<span class="hl str">    undef;</span>
<span class="hl str">}</span>
<span class="hl str"></span>
<span class="hl str">sub suggest_mount_point {</span>
<span class="hl str">    my (</span><span class="hl ipl">$e</span><span class="hl str">) =</span> <span class="hl ipl">&#64;_</span><span class="hl str">;</span>
<span class="hl str"></span>
<span class="hl str">    my</span> <span class="hl ipl">$name</span> <span class="hl str">=</span> <span class="hl ipl">$e</span><span class="hl str">-&gt;{media_type};</span>
<span class="hl str">    if (member(</span><span class="hl ipl">$e</span><span class="hl str">-&gt;{media_type}, &apos;hd&apos;, &apos;fd&apos;)) {</span>
<span class="hl str">	if (exists</span> <span class="hl ipl">$e</span><span class="hl str">-&gt;{usb_driver}) {</span>
<span class="hl str"></span>	    <span class="hl ipl">$name</span> <span class="hl str">= usb2removable(</span><span class="hl ipl">$e</span><span class="hl str">) || &apos;removable&apos;;</span>
<span class="hl str">	} elsif (isZipDrive(</span><span class="hl ipl">$e</span><span class="hl str">)) {</span>
<span class="hl str"></span>	    <span class="hl ipl">$name</span> <span class="hl str">= &apos;zip&apos;;</span>
<span class="hl str">	} elsif (</span><span class="hl ipl">$e</span><span class="hl str">-&gt;{media_type} eq &apos;fd&apos;) {</span>
<span class="hl str"></span>	    <span class="hl ipl">$name</span> <span class="hl str">= &apos;floppy&apos;;</span>
<span class="hl str">	} else {</span>
<span class="hl str">	    log::l(&quot;</span>suggest_mount_point<span class="hl opt">:</span> <span class="hl kwa">do</span> <span class="hl kwc">not</span> know what to with hd <span class="hl kwb">$e</span><span class="hl opt">-&gt;{</span>device<span class="hl opt">}</span><span class="hl str">&quot;);</span>
<span class="hl str">	}</span>
<span class="hl str">    }</span>
<span class="hl str"></span>    <span class="hl ipl">$name</span><span class="hl str">;</span>
<span class="hl str">}</span>
<span class="hl str"></span>
<span class="hl str">1;</span>
<span class="hl str"></span>
<span class="hl str">#- Local Variables:</span>
<span class="hl str">#- mode:cperl</span>
<span class="hl str">#- tab-width:8</span>
<span class="hl str">#- End:</span>
</code></pre></td></tr></table>
</div> <!-- class=content -->
<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit v1.2.1</a> (<a href='https://git-scm.com/'>git 2.21.0</a>) at 2025-03-01 05:01:26 +0000</div>
</div> <!-- id=cgit -->
</body>
</html>