package modules; # $Id$ use strict; use common; use detect_devices; use run_program; use log; use list_modules; our %conf; sub category2modules_and_description { my ($categories) = @_; my $f = '/lib/modules/' . c::kernel_version() . '/modules.description'; -e $f or $f = '/lib/modules.description'; my %modules_descriptions = map { /(\S+)\s+(.*)/ } cat_($f); map { $_ => $modules_descriptions{$_} } category2modules($categories); } #-############################################################################### #- module loading #-############################################################################### # handles dependencies # eg: load('vfat', 'reiserfs', [ ne2k => 'io=0xXXX', 'dma=5' ]) sub load { #- keeping the order of modules my %options; my @l = map { my ($name, @options) = ref $_ ? @$_ : $_; $options{$name} = \@options; dependencies_closure($name); } @_; @l = difference2([ uniq(@l) ], [ loaded_modules() ]) or return; my $network_module = do { my ($network_modules, $other) = partition { module2category($_) =~ m,network/(main|usb), } @l; if (@$network_modules > 1) { # do it one by one load($_) foreach @$network_modules; load(@$other); return; } $network_modules->[0]; }; my @network_devices = $network_module ? detect_devices::getNet() : (); if ($::testing) { log::l("i would load module $_ (@{$options{$_}})") foreach @l; } elsif ($::isStandalone || $::live) { run_program::run('/sbin/modprobe', $_, @{$options{$_}}) or die "insmod'ing module $_ failed" foreach @l; } else { load_raw(map { [ $_ => $options{$_} ] } @l); } sleep 2 if grep { /^(usb-storage|mousedev|printer)$/ } @l; if ($network_module) { add_alias($_, $network_module) foreach difference2([ detect_devices::getNet() ], \@network_devices); } when_load($_, @{$options{$_}}) foreach @l; } sub unload { if ($::testing) { log::l("rmmod $_") foreach @_; } else { run_program::run("rmmod", $_) foreach @_; } } sub load_category { my ($category, $wait_message, $probe_type) = @_; #- probe_category returns the PCMCIA cards. It doesn't know they are already #- loaded, so: read_already_loaded(); my @try_modules = ( if_($category =~ /scsi/, if_(arch() !~ /ppc/, 'imm', 'ppa'), if_(detect_devices::usbStorage(), 'usb-storage'), ), if_(arch() =~ /ppc/, if_($category =~ /scsi/, 'mesh', 'mac53c94'), if_($category =~ /net/, 'bmac', 'gmac', 'mace'), if_($category =~ /sound/, 'dmasound_awacs'), ), ); grep { $wait_message->($_->{description}, $_->{driver}) if $wait_message; eval { load([ $_->{driver}, $_->{options} ]) }; $_->{error} = $@; !($@ && $_->{try}); } probe_category($category, $probe_type), map { { driver => $_, description => $_, try => 1 } } @try_modules; } sub probe_category { my ($category, $probe_type) = @_; my @modules = category2modules($category); grep { if ($category eq 'isdn') { my $b = $_->{driver} =~ /ISDN:([^,]*),?([^,]*),?(.*)/; if ($b) { $_->{driver} = $1; $_->{options} = $2; $_->{firmware} = $3; $_->{firmware} =~ s/firmware=//; $_->{driver} eq "hisax" and $_->{options} .= " id=HiSax"; } $b; } else { member($_->{driver}, @modules); } } detect_devices::probeall($probe_type); } sub load_ide { eval { load("ide-cd") } } #-############################################################################### #- modules.conf functions #-############################################################################### sub get_alias { my ($alias) = @_; $conf{$alias}{alias}; } sub get_probeall { my ($alias) = @_; $conf{$alias}{probeall}; } sub get_options { my ($name) = @_; $conf{$name}{options}; } sub set_options { my ($name, $new_option) = @_; $conf{$name}{options} = $new_option; } sub add_alias { my ($alias, $module) = @_; $module =~ /ignore/ and return; /\Q$alias/ && $conf{$_}{alias} && $conf{$_}{alias} eq $module and return $_ foreach keys %conf; log::l("adding alias $alias to $module"); $conf{$alias}{alias} ||= $module; $conf{$module}{above} = 'snd-pcm-oss' if $module =~ /^snd-/; $alias; } sub add_probeall { my ($alias, $module) = @_; my $l = $conf{$alias}{probeall} ||= []; @$l = uniq(@$l, $module); log::l("setting probeall scsi_hostadapter to @$l"); } sub remove_alias($) { my ($name) = @_; foreach (keys %conf) { $conf{$_}{alias} && $conf{$_}{alias} eq $name or next; delete $conf{$_}{alias}; return 1; } 0; } sub read_conf { my ($file) = @_; my %c; foreach (cat_($file)) { next if /^\s*#/; my ($type, $alias, $val) = split(/\s+/, chomp_($_), 3) or next; $val = [ split ' ', $val ] if $type eq 'probeall'; $c{$alias}{$type} = $val; } #- cheating here: not handling aliases of aliases while (my ($k, $v) = each %c) { if (my $a = $v->{alias}) { local $c{$a}{alias}; delete $v->{probeall}; add2hash($c{$a}, $v); } } #- convert old aliases to new probeall foreach my $name ('scsi_hostadapter', 'usb-interface') { my @old_aliases = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { if_(/^$name(\d*)/ && $c{$_}{alias}, [ $_, $1 || 0 ]) } keys %c; foreach my $alias (@old_aliases) { push @{$c{$name}{probeall} ||= []}, delete $c{$alias}{alias}; } } \%c; } sub mergein_conf { my ($file) = @_; my $modconfref = read_conf($file); while (my ($key, $value) = each %$modconfref) { $conf{$key}{alias} = $value->{alias} if !exists $conf{$key}{alias}; push @{$conf{$key}{probeall} ||= []}, deref($value->{probeall}); } } sub write_conf { my ($prefix) = @_; my $file = "$prefix/etc/modules.conf"; rename "$prefix/etc/conf.modules", $file; #- make the switch to new name if needed #- Substitute new aliases in modules.conf (if config has changed) substInFile { my ($type,$alias,$module) = split(/\s+/, chomp_($_), 3); if ($type eq 'post-install' && $alias eq 'supermount') { #- remove the post-install supermount stuff. $_ = ''; } elsif ($type eq 'alias' && $alias =~ /scsi_hostadapter|usb-interface/) { #- remove old aliases which are replaced by probeall $_ = ''; } elsif ( $conf{$alias}{$type} && $conf{$alias}{$type} ne $module) { my $v = join(' ', uniq(deref($conf{$alias}{$type}))); $_ = "$type $alias $v\n"; } } $file; my $written = read_conf($file); local *F; open F, ">> $file" or die("cannot write module config file $file: $!\n"); while (my ($mod, $h) = each %conf) { while (my ($type, $v) = each %$h) { my $v2 = join(' ', uniq(deref($v))); print F "$type $mod $v2\n" if $v2 && !$written->{$mod}{$type}; } } my @l; push @l, 'scsi_hostadapter' if !is_empty_array_ref($conf{scsi_hostadapter}{probeall}); push @l, 'bttv' if grep { $_->{driver} eq 'bttv' } detect_devices::probeall(); append_to_etc_modules($prefix, @l); }