1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
#!perl -w
#
# ModProbe -- insert modules plus dependencies
# Copyright (C) 2005 Erik van Konijnenburg
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# This uses modprobe to determine which files to load to get a certain
# module. It adds two extra features:
# - do not load blacklisted modules
# - if we know a module is compiled into the kernel,
# don't attempt to load it, and don't complain.
#
# Notes on the behaviour of modprobe:
#
# modprobe --verbose --dry-run --show-depends --set-version 2.6.11 aes
#
# shows the files that are needed, regardless of whether they are
# already loaded. Lines start with 'insmod ' for files to be loaded,
# or 'install ' for commands to be executed.
#
# Modprobe file format:
# - characters are bytes, no messing with utf-8.
# - backslash at end of line merges lines
# - other \x get replaced by x
# - ^\s*# lines are ignored
# - lines without : are ignored.
# This means "aap: noot.#7" is a valid dependency.
# The backslash interpretation is mostly for modprobe.conf;
# depmod does not generate it.
#
# Modprobe determines module name by dropping everything after dot:
# "/lib/noot.#7" is module "noot". We'll adopt the same policy.
#
# Depmod only grabs modules ending in .ko or .ko.gz.
#
# Note that modprobe does not discriminate against modules outside
# /lib/modules: if it's listed in modules.dep, it's a valid module.
#
# Note that redhat has a convention that modules in .../update take
# precedence over other modules with the same name. Depmod implements
# this by not putting modules that are overridden in modules.dep.
# Thus modprobe needs no special action to support that convention.
#
# The logic modprobe uses to determine which modules to load:
# - replace hyphens with underscore
# - read config specified on command line,
# OR modprobe.conf OR modprobe.d, only first one found.
# Remember all "install" and "option" directives,
# rewrite module name if an alias matches
# - if no alias found and the name is of the form 'symbol:xxx':
# look in modules.symbols to resolve to a module name
# - if alias found:
# make a list of modules to load, based on modules.dep
# - else:
# make a list of modules to load, based on modules.dep
# if that turned up no modules AND there was no install cmd:
# - look in modules.aliases to resolve to modulename
# - make a list of modules to load, based on modules.dep
# - if the list to load is empty AND there was no install command:
# - complain.
# # in insmod():
# - recurse over the module list, most basic stuff first, doing:
# - if there is a command for this module name:
# execute it
# - else:
# load the module
#
# Loading of the module is done with a system call. The option string
# is passed as third argument; splitting the option string in separate
# module options is done in the kernel. Double quote escapes spaces,
# double quotes themselves cannot be escaped.
#
use strict;
use warnings;
use Base;
use Conf;
use ActionList;
use Blacklist;
use KConfig;
package ModProbe;
#
# addModules -- given an actionList and list of modules,
# add actions to load all modules, plus their dependencies,
# unless blacklisted or compiled in.
#
sub addModules ($$) {
my ($actionList, $modList) = @_;
addOptModules ($actionList, $modList, 0);
}
# addOptModules -- the same except:
# If optional, ignore modules that are not found.
sub addOptModules ($$$) {
my ($actionList, $modList, $optional) = @_;
for my $moduleName (@{$modList}) {
if (Blacklist::isBlacklisted ($moduleName)) {
next;
}
if (KConfig::isBuiltIn ($moduleName)) {
next;
}
addOneModule ($actionList, $moduleName, $optional);
}
}
#
# addOneModule -- for one module, that is not blacklisted or compiled in,
# add actions to load it plus all its dependencies.
# If optional, ignore modules that are not found.
#
sub addOneModule ($$$) {
my ($actionList, $m, $optional) = @_;
my $v = Conf::get('version');
Base::debug ("addOneModule: modprobe $m");
my ($rc, $lines) = Base::runCmd (
failOk => $optional,
cmd => ['/sbin/modprobe', '-v', '-n',
'--show-depends', '--set-version', $v, $m]);
if (! $rc) {
# modprobe failed; assume it's because of not found
return;
}
for my $line (@{$lines}) {
$line =~ s/\s+$//;
if ($line =~ /^install (.*)/) {
# Since we're using modprobe output,
# we cannot refer to location of the
# offending line in config file.
Base::fatal ("modprobe shows that module $m needs an external program; this is not supported. The offending line is: install $1");
}
elsif ($line =~ /^insmod (\S+)$/) {
$actionList->add ("insmod", $1,
optionList => '');
}
elsif ($line =~ /^insmod (\S+)\s+(.*)$/) {
my $file = $1;
my $option = $2;
# This should allow options in modprobe.conf
# to contain both ' and " characters and spaces.
$option =~ s![^a-zA-Z0-9,_./=-]!\\$&!g;
$actionList->add ("insmod", $file,
optionList => $option);
}
else {
Base::fatal ("modprobe $m - unsupported output $line");
}
}
}
1;
|