]> git.sur5r.net Git - bacula/rescue/blob - rescue/linux/cdrom/yaird-0.0.5/perl/ModDepTab.pm
Initial revision
[bacula/rescue] / rescue / linux / cdrom / yaird-0.0.5 / perl / ModDepTab.pm
1 #!perl -w
2 #
3 # ModDepTab -- encapsulate modprobe(8)
4 #   Copyright (C) 2005  Erik van Konijnenburg
5 #
6 #   This program is free software; you can redistribute it and/or modify
7 #   it under the terms of the GNU General Public License as published by
8 #   the Free Software Foundation; either version 2 of the License, or
9 #   (at your option) any later version.
10 #
11 #   This program is distributed in the hope that it will be useful,
12 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #   GNU General Public License for more details.
15 #
16 #   You should have received a copy of the GNU General Public License
17 #   along with this program; if not, write to the Free Software
18 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 #
20 # Most important routine is resolve(), which returns a list of
21 # modules with dependencies resolved.
22 #
23 # For every module, we have a list of prerequisite modules;
24 # these prerequisites are in no particular order: the prerequisites
25 # may have dependencies among themselves that are not satisfied
26 # by the order in the list.
27 #
28 # This emulates modprobe(8) by interpreting /lib/modules/2.6.x/modules.dep.
29 # Input format:
30 #  - characters are bytes, no messing with utf-8.
31 #  - backslash at end of line merges lines
32 #  - other \x get replaced by x
33 #  - ^\s*# lines are ignored
34 #  - lines without : are ignored.
35 # This means "aap: noot.#7" is a valid dependency.
36 # The backslash interpretation is mostly for modprobe.conf;
37 # depmod does not generate it.
38 #
39 # Modprobe determines module name by dropping everything after dot:
40 # "/lib/noot.#7" is module "noot".  We'll adopt the same policy.
41 #
42 # Note that depmod only grabs modules ending in .ko or .ko.gz;
43 # we'll issue a warning if a module has a different suffix.
44 #
45 # Note that modprobe does not discriminate against modules outside
46 # /lib/modules: if it's listed in modules.dep, it's a valid module.
47 #
48 # Note that redhat has a convention that modules in .../update take
49 # precedence over other modules with the same name.  Depmod implements
50 # this by not putting modules that are overridden in modules.dep.
51 # Thus modprobe and yaird need no special action to support that convention.
52 #
53 # The logic modprobe uses to determine which modules to load:
54 # - replace hyphens with underscore
55 # - read config specified on command line,
56 #   OR modprobe.conf OR modprobe.d, only first one found.
57 #   Remember all "install" and "option" directives,
58 #   rewrite module name if an alias matches
59 # - if no alias found and the name is of the form 'symbol:xxx':
60 #       look in modules.symbols to resolve to a module name
61 # - if alias found:
62 #       make a list of modules to load, based on modules.dep
63 # - else:
64 #       make a list of modules to load, based on modules.dep
65 #       if that turned up no modules AND there was no install cmd:
66 #               - look in modules.aliases to resolve to modulename
67 #               - make a list of modules to load, based on modules.dep
68 # - if the list to load is empty AND there was no install command:
69 #       - complain.
70 # # in insmod():
71 # - recurse over the module list, most basic stuff first, doing:
72 #       - if there is a command for this module name:
73 #               execute it
74 #       - else:
75 #               load the module
76 #
77 # We probably should replace this perl module with parsing the
78 # output of modprobe --verbose --dry-run --show-depends --set-version,
79 # but that requires changes in the calling modules, and there's discussion
80 # of adding blacklist support to modprobe, so for now, let's not.
81 #
82
83 use strict;
84 use warnings;
85 use Base;
86 use Conf;
87 use ModDep;
88 use KConfig;
89
90 package ModDepTab;
91
92 my $modDepTab = undef;
93 my $modDepList = undef;
94
95 sub init () {
96         if (defined ($modDepTab)) {
97                 return;
98         }
99         $modDepTab = {};
100         my $name = Conf::get('modDep');
101         if (! open (IN, "<", "$name")) {
102                 Base::fatal ("can't open $name");
103         }
104         my $lineNo = 0;
105         while (defined (my $line = <IN>)) {
106                 $lineNo++;
107                 chomp $line;
108
109                 # it would be nice to ignore leading and trailing
110                 # space, and to allow # comment at end of line.
111                 # however, that's not how modprobe does it,
112                 # so we shouldn't either.
113                 next if $line =~ /^\s*#/;
114
115                 if ($line =~ /^(.*):\s*(.*)$/) {
116                         my $file = $1;
117                         my $val = $2;
118                         my $key = $file;
119
120                         if ($key !~ /\.ko$/  && $key !~ /\.ko\.gz/) {
121                                 Base::warning ("$name:$lineNo: odd module name: $key");
122                         }
123                         $key =~ s!.*/!!;
124                         $key =~ s!\..*$!!;
125                         $key =~ s!_!-!g;
126
127                         my @fields = split (/\s+/, $val);
128                         for my $i (0 .. $#fields) {
129                                 # strip pathname and extension from
130                                 # required modules, normalise underscore.
131                                 # dont complain about odd suffix.
132                                 $fields[$i] =~ s!.*/!!;
133                                 $fields[$i] =~ s!\..*$!!;
134                                 $fields[$i] =~ s!_!-!g;
135                         }
136                         
137                         my $conflict = $modDepTab->{$key};
138                         if (defined ($conflict)) {
139                                 my $origin = $conflict->origin();
140                                 Base::warning ("$name:$lineNo: $key overrules earlier definition at $origin");
141                         }
142
143                         $modDepTab->{$key} = ModDep->new (
144                                 name => $key,
145                                 file => $file,
146                                 origin => "$name:$lineNo",
147                                 deps => [ @fields ],
148                                 );
149                 }
150                 else {
151                         Base::warning ("$name:$lineNo: malformed line ignored");
152                 }
153                 
154         }
155         if (! close (IN)) {
156                 Base::fatal ("could not read $name");
157         }
158         $modDepList = [ sort keys %{$modDepTab} ];
159 }
160
161 sub all () {
162         init;
163         return $modDepList;
164 }
165
166 sub findByModnam ($) {
167         my ($module) = @_;
168         init;
169         $module =~ s!_!-!g;
170         my $result = $modDepTab->{$module};
171         if (! defined ($result)) {
172                 Base::fatal ("can't find dependencies for $module");
173         }
174         return $result;
175 }
176
177
178 # return a copy of the list with prerequisite modules inserted
179 sub resolve ($) {
180         my ($modList) = @_;
181         Base::debug ("resolving: " . join (',', @{$modList}) . '.');
182         my $result = [];
183         resolve2 ($modList, $result);
184         Base::debug ("resolved to: " . join (',', @{$result}) . '.');
185         return $result;
186 }
187
188 #
189 # resolve2 -- given a list of modules, that may have dependencies
190 # (even among themselves) and a list of modules that is in proper order
191 # to be loaded without unresolved dependencies,
192 # add everything from the first list (plus their dependencies)
193 # to the second list, without introducing duplicates.
194 #
195 sub resolve2 ($$);
196 sub resolve2 ($$) {
197         my ($modList, $done) = @_;
198 OUTER:  for my $module (@{$modList}) {
199                 #
200                 # Stuff that is compiled into the kernel cannot
201                 # add or resolve dependencies, and obviously don't
202                 # need to be loaded.  Drop them from the list.
203                 #
204                 if (KConfig::isBuiltIn ($module)) {
205                         next OUTER;
206                 }
207                 #
208                 # if the module is already there, don't add again
209                 #
210                 for my $d (@{$done}) {
211                         if ($d eq $module) {
212                                 next OUTER;
213                         }
214                 }
215                 #
216                 # recursively add prerequisites
217                 #
218                 my $deps = ModDepTab::findByModnam($module);
219                 if (! defined ($deps)) {
220                         Base::fatal ("can't find dependencies for $module");
221                 }
222                 resolve2 ($deps->deps, $done);
223                 #
224                 # and module itself
225                 #
226                 push @{$done}, $module;
227         }
228 }
229
230 1;