source: soft/build_system/build_system/iurt/trunk/lib/Iurt/DKMS.pm @ 1

Last change on this file since 1 was 1, checked in by fasma, 12 years ago

Initial Import from Mandriva's soft revision 224062 and package revision 45733

File size: 11.8 KB
Line 
1package Iurt::DKMS;
2
3use strict;
4use base qw(Exporter);
5use MDV::Distribconf::Build;
6use Iurt::Chroot qw(clean_chroot add_local_user dump_rpmmacros);
7use Iurt::Config qw(get_maint get_prefix dump_cache init_cache);
8use File::NCopy qw(copy);
9use Iurt::Process qw(sudo);
10use Iurt::Util qw(plog);
11use RPM4::Header;
12use MDK::Common;
13
14our @EXPORT = qw(
15        search_dkms
16        dkms_compile
17);
18
19sub new {
20    my ($class, %opt) = @_;
21    my $self = bless {
22        config  => $opt{config},
23        run => $opt{run},
24    }, $class;
25
26    $self;
27}
28
29=head2 search_dkms($run, $config)
30
31Search for dkms packages which needs to be recompiled for new kernel
32I<$run> is the running environment
33I<%config> is the current configuration values
34Return true.
35
36=cut
37
38sub search_dkms {
39    my ($self) = @_;
40    my $config = $self->{config};
41    my $run = $self->{run};
42    my $arch = $run->{my_arch};
43    my $root = $config->{repository};
44    my $distro = $run->{distro};
45    my $cache = $run->{cache};
46    my $path = "$root/$distro/$arch";
47    if (!-d $path) {
48        plog('ERR', "ERROR: $path is not a directory");
49        return;
50    }
51    my $distrib = MDV::Distribconf::Build->new($path);
52    plog("getting media config from $path");
53    if (!$distrib->loadtree) {
54        plog('ERR', "ERROR: $path does not seem to be a distribution tree");
55        return;
56    }
57    $distrib->parse_mediacfg;
58    my %dkms;
59    my @kernel;
60    my %modules;
61    my %kernel_source;
62    foreach my $media ($distrib->listmedia) {
63        $media =~ /(SRPMS|debug_)/ and next;
64        my $path = $distrib->getfullpath($media, 'path');
65        my $media_ok = $run->{dkms}{media} ? $media =~ /$run->{dkms}{media}/ : 1;
66        my $kmedia_ok = $run->{dkms}{kmedia} ? $media =~ /$run->{dkms}{kmedia}/ : 1;
67        plog("searching in $path");
68        opendir my $rpmdh, $path;
69        foreach my $rpm (readdir $rpmdh) {
70            if ($rpm =~ /^dkms-(.*)-([^-]+-[^-]+)\.[^.]+\.rpm/) {
71                # we only check for kernel or modules in this media
72                $media_ok or next;
73                my $hdr = RPM4::Header->new("$path/$rpm");
74                my $files = $hdr->queryformat('[%{FILENAMES} ])');
75                my ($name, $version) = ($1, $2);
76                my ($modulesourcedir) = $files =~ m, /usr/src/([^/ ]+),;
77                my $script = $hdr->queryformat('%{POSTIN})');
78                my ($realversion) = $script =~ / -v (\S+)/;
79                plog('NOTIFY', "dkms $name version $version source $modulesourcedir realversion $realversion");
80                push @{$dkms{$media}}, [ $name, $version, $modulesourcedir, $realversion, "$path/$rpm" ];
81            } elsif ($rpm =~ /^kernel-((?:[^-]+-)?[^-]+.*)-[^-]+-[^-]+\.[^.]+\.rpm/ && $rpm !~ /win4lin|latest|debug|stripped|BOOT|xen|doc/) {
82                # we do not check for kernel in this media
83                $kmedia_ok or next;
84                my $hdr = RPM4::Header->new("$path/$rpm");
85                my $files = $hdr->queryformat('[%{FILENAMES} ])');
86                my $version = $1;
87                if ($version =~ /(.*)source-(.*)/) {
88                    my $source = "$1$2";
89                    my ($sourcedir) = $files =~ m, /usr/src/([^/ ]+),;
90                    plog('NOTIFY', "kernel source $version ($source sourcedir $sourcedir)");
91                    $kernel_source{$source} = [ $version, $sourcedir ];
92                } else {
93                    my ($modulesdir) = $files =~ m, /lib/modules/([^/ ]+),;
94                    plog('NOTIFY', "kernel $version (modules dir $modulesdir)");
95                    push @kernel, [ $version, $modulesdir ];
96                }
97            } elsif ($rpm =~ /^(.*)-kernel-([^-]+-[^-]+.*)-([^-]+-[^-]+)\.[^.]+\.rpm$/) {
98                plog('NOTIFY', "modules $1 version $3 for kernel $2");
99                # module version kernel
100                $modules{$1}{$3}{$2} = 1;
101            }
102        }
103    }
104    my $nb;
105    foreach my $media (keys %dkms) {
106        foreach my $dkms (@{$dkms{$media}}) {
107            my ($module, $version, $modulesourcedir, $realversion, $file) = @$dkms;
108            foreach my $k (@kernel) {
109                my ($kernel, $modulesdir) = @$k;
110                plog("checking $module-kernel-$modulesdir-$realversion");
111                next if $cache->{dkms}{"$module-kernel-$modulesdir-$realversion"} && !$run->{ignore_failure};
112                if (!$modules{$module}{$version}{$modulesdir}) {
113                    my ($name, $v) = $kernel =~ /^([^-]+)-.*-(2\..*)/;
114                    my $source = "$name-$v";
115                    if (!$kernel_source{$source}) {
116                        my ($name) = $kernel =~ /(2\..*)/;
117                        plog('ERR', "ERROR: no source for kernel $kernel (source $source), testing $name");
118                        $source = $name;
119                        if (!$kernel_source{$source}) {
120                            my $name = $kernel;
121                            plog('ERR', "ERROR: no source for kernel $kernel (source $source), testing $name");
122                            $source = $name;
123                            if (!$kernel_source{$source}) {
124                                plog('ERR', "ERROR: no source for kernel $kernel (source $source), ignoring");
125                                next;
126                            }
127                        }
128                    }
129                    plog("dkms module $module version $version should be compiled for kernel $kernel ($source)");
130                    $nb++;
131                    push @{$run->{dkms_todo}}, [ $module, $version, $modulesourcedir, $realversion, $file, $kernel, $modulesdir, @{$kernel_source{$source}}, $media ];
132                }
133                $modules{$module}{$version}{$modulesdir}++;
134            }
135        }
136    }
137    foreach my $module (keys %modules) {
138        foreach my $version (keys %{$modules{$module}}) {
139            foreach my $modulesdir (keys %{$modules{$module}{$version}}) {
140                next if $modules{$module}{$version}{$modulesdir} < 2;
141                plog('WARN', "dkms module $module version $version for kernel $modulesdir is obsolete");
142                push @{$run->{dkms_obsolete}}, "$module-kernel-$modulesdir-$version";
143            }
144        }
145    }
146    $nb;
147}
148
149=head2 dkms_compile($class, $local_spool, $done)
150
151Compile the dkms against the various provided kernel
152Return true.
153
154=cut
155
156sub dkms_compile {
157    my ($self, $local_spool, $done) = @_;
158    my $config = $self->{config};
159    my $run = $self->{run};
160    my $urpmi = $run->{urpmi};
161    # For dkms build, the chroot is only installed once and the all the modules are recompiled
162    my $chroot_tmp = $run->{chroot_tmp};
163    my $chroot_tar = $run->{chroot_tar};
164    my $cache = $run->{cache};
165    my $luser = $run->{user};
166    my $to_compile = $run->{to_compile};
167
168    plog("building chroot: $chroot_tmp");
169    clean_chroot($chroot_tmp, $chroot_tar, $run, $config);
170    my %installed;
171    # initialize urpmi command
172    $urpmi->urpmi_command($chroot_tmp, $luser);
173    # also add macros for root
174    add_local_user($chroot_tmp, $run, $config, $luser, $run->{uid});
175
176    if (!dump_rpmmacros($run, $config, "$chroot_tmp/home/$luser/.rpmmacros") || !dump_rpmmacros($run, $config, "$chroot_tmp/root/.rpmmacros")) {
177        plog('ERR', "ERROR: adding rpmmacros failed");
178        return;
179    }
180
181    my $kerver = `uname -r`;
182    chomp $kerver;
183
184    my $dkms_spool = "$local_spool/dkms/";
185    -d $dkms_spool or mkdir $dkms_spool;
186
187    for (my $i; $i < @{$run->{dkms_todo}}; $i++) {
188        my ($name, $version, $_modulesourcedir, $realversion, $file, $kernel, $modulesdir, $source, $sourcedir, $media) = @{$run->{dkms_todo}[$i]};
189        $done++;
190
191        plog("dkms modules $name version $version for kernel $kernel [$done/$to_compile]");
192
193        # install kernel and dkms if not already installed
194        my $ok = 1;
195        # some of the dkms modules does not handle correclty the -k option and use uname -r to
196        # find kernel modules dir.
197        # FIXME must send a mail to the maintainer for that problem
198        # try to workarround with a symlink
199        if ($kerver ne $modulesdir) {
200            if (-e "$chroot_tmp/lib/modules/$kerver") {
201                system("sudo mv $chroot_tmp/lib/modules/$kerver $chroot_tmp/lib/modules/$kerver.tmp");
202            }
203            if (system("sudo ln -sf $modulesdir $chroot_tmp/lib/modules/$kerver")) {
204                plog('ERR', "ERROR: creating a link from $chroot_tmp/lib/modules/$modulesdir to $kerver failed ($!)");
205                next;
206            }
207        }
208        foreach my $pkg ("kernel-$source", "dkms", "kernel-$kernel", $file) {
209            my $pkgname = basename($pkg);
210            if ($run->{chrooted_urpmi} && -f $pkg) {
211                copy $pkg, "$chroot_tmp/tmp/";
212                $pkg = "/tmp/$pkgname";
213            }
214            if (!$installed{$pkg}) {
215                plog('DEBUG', "install package: $pkg");
216                if (!$urpmi->install_packages("dkms-$name-$version", $chroot_tmp, $local_spool, {}, "dkms_$pkgname", "[DKMS] package $pkg installation error", { maintainer => $config->{admin} }, $pkg)) {
217                    plog('ERR', "ERROR: error installing package $pkg");
218                    $ok = 0;
219                    last;
220                }
221                $installed{$pkg} = 1;
222            }
223            # recreate the appropriate kernel source link
224        }
225        $ok or next;
226
227        plog('DEBUG', "symlink from /lib/modules/$modulesdir/build to /usr/src/$sourcedir");
228
229        if (system("sudo ln -sf /usr/src/$sourcedir $chroot_tmp/lib/modules/$modulesdir/build")) {
230            plog('ERR', "linking failed ($!)");
231            next;
232        }
233        # seems needed for some kernel
234        system("cd $chroot_tmp/usr/src/$sourcedir && sudo make prepare");
235        # If the dkms packages get installed, the modules is correclty built
236        # but if we just compile it for a new kernel, we need to rebuild it manually
237
238        foreach my $cmd ('add', 'build') {
239            my $command = "TMP=/home/$luser/tmp/ sudo chroot $chroot_tmp /usr/sbin/dkms $cmd -m $name -v $realversion --rpm_safe_upgrade -k $modulesdir --kernelsourcedir=/usr/src/$sourcedir";
240            plog('DEBUG', "execute: $command");
241            system($command);
242        }
243
244        # now need to move dkms build if it wrongly assume a build for the running kernel
245        plog("search module in /var/lib/dkms/$name/$version/$kerver/");
246        if (-d "$chroot_tmp/var/lib/dkms/$name/$version/$kerver/") {
247            system("sudo mv $chroot_tmp/var/lib/dkms/$name/$realversion/$kerver/ $chroot_tmp/var/lib/dkms/$name/$realversion/$modulesdir/");
248        }
249        $cache->{dkms}{"$name-kernel-$modulesdir-$realversion"} = 1;
250        if (system("sudo chroot $chroot_tmp /usr/sbin/dkms mkrpm -m $name -v $realversion --rpm_safe_upgrade -k $modulesdir")) {
251            plog('FAIL', "build failed ($!)");
252            next;
253        }
254
255        plog('OK', "build succesful, copy packages to $dkms_spool/$media");
256
257        -d "$dkms_spool/$media" or mkdir_p "$dkms_spool/$media";
258
259        system("cp $chroot_tmp/home/$luser/rpm/RPMS/*/*.rpm $dkms_spool/$media/ &>/dev/null") && system("cp $chroot_tmp/usr/src/rpm/RPMS/*/*.rpm $dkms_spool/$media/ &>/dev/null") and $run->{LOG}->("ERROR: could not copy dkms packages from $chroot_tmp/usr/src/rpm/RPMS/*/*.rpm or $chroot_tmp/home/$luser/rpm/RPMS/*/*.rpm to $dkms_spool/$media ($!)\n");
260        !sudo($run, $config, '--rm', "$chroot_tmp/home/$luser/rpm/RPMS/*/*.rpm") || !sudo($run, $config, '--rm', "$chroot_tmp/usr/src/rpm/RPMS/*/*.rpm") and $run->{LOG}->("ERROR: could not delete dkms packages from $chroot_tmp/usr/src/rpm/RPMS/*/*.rpm or $chroot_tmp/home/$luser/rpm/RPMS/*/*.rpm ($!)\n");
261
262        if ($kerver ne $modulesdir) {
263            system("sudo rm -f $kerver $chroot_tmp/lib/modules/$modulesdir");
264            if (-e "$chroot_tmp/lib/modules/$kerver.tmp") {
265                system("sudo mv $chroot_tmp/lib/modules/$kerver.tmp $chroot_tmp/lib/modules/$kerver");
266            }
267        }
268        process_dkms_queue($self, 0, 0, $media, "$dkms_spool/$media");
269        # compile dkms modules
270    }
271    dump_cache($run);
272    $done;
273} 
274# FIXME will replace the iurt2 process_qeue when youri-queue is active
275sub process_dkms_queue {
276    my ($self, $wrong_rpm, $quiet, $media, $dir) = @_;
277    my $run = $self->{run};
278    return if !$run->{upload} && $quiet;
279    my $config = $self->{config};
280    my $cache = $run->{cache};
281    $media ||= $run->{media};
282    my $urpmi = $run->{urpmi};
283
284    $dir ||= "$config->{local_upload}/iurt/$run->{distro_tag}/$run->{my_arch}/$media}/";
285
286    plog("processing $dir");
287    opendir my $rpmdir, $dir or return;
288    # get a new prefix for each package so that they will not be all rejected if only one is wrong
289    my $prefix = get_prefix('iurt');
290    foreach my $rpm (readdir $rpmdir) {
291        my ($rarch, $srpm) = $urpmi->update_srpm($dir, $rpm, $wrong_rpm);
292        $rarch or next;
293        plog('DEBUG', $rpm);
294        next if !$run->{upload};
295
296        plog("copy $rpm to $config->{upload_queue}/$run->{distro}/$media/");
297
298        # recheck if the package has not been uploaded in the meantime
299        my $rpms_dir = "$config->{repository}/$run->{distro}/$run->{my_arch}/media/$media/";
300        if (! -f "$rpms_dir/$rpm") {
301            my $err = system("/usr/bin/scp", "$dir/$rpm", $config->{upload_queue} . "/$run->{distro}/$media/$prefix$rpm");
302            # try to keep the opportunity to prevent disk full "
303            if ($err) {
304                #$run->{LOG}->("ERROR process_queue: cannot copy $dir/$rpm to ", $config->{upload_queue}, "/$run->{distro}/$media/$prefix$rpm ($!)\n");
305                next;
306            }
307        }
308        if ($run->{upload_source}) {
309            #should not be necessary
310        }
311        # should not be necessary to use sudo
312        sudo($run, $config, '--rm', "$dir/$rpm");
313        $cache->{queue}{$srpm} = 1;
314    }
315    closedir $rpmdir;
316}
317
3181;
Note: See TracBrowser for help on using the repository browser.