4 # Check and possibly rebuild lufs kernel module for the current kernel.
5 # Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; exactly version 2 of June 1991 is required
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.
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
22 use Carp qw(cluck confess);
24 # Do not use any non-core Perl modules here.
25 # Be perl-5.0 compatible (is it needed if we require Linux kernel >= 2.4 ?)
28 my $basedir='@datadir@/lufs';
29 my $vardir='@localstatedir@/lib/lufs';
30 $basedir=~s#\$\Q{prefix}\E#'@prefix@';#ge;
31 $vardir=~s#\$\Q{prefix}\E#'@prefix@';#ge;
32 $vardir="" if $vardir=~/^@/;
33 sub srcdir { my($uname_r)=@_; $basedir."/".($uname_r lt "2.5" ? "2.4" : "2.5"); }
34 my $modbindir=$basedir."/modbin";
35 my @sources=qw(proc.c inode.c dir.c file.c symlink.c);
40 use vars qw($kernel_gcc_args);
44 if ($0 eq "lufsmnt" || $0=~m#/lufsmnt$#) {
46 $lufsmnt_bin='@bindir@/lufsmnt-bin';
47 $lufsmnt_bin=~s#\$\Q{exec_prefix}\E#'@exec_prefix@';#ge;
48 $lufsmnt_bin=~s#\$\Q{prefix}\E#'@prefix@';#ge;
53 "kernel",\$kernel, # it must contain "include" subdir
54 "modbindir=s",\$modbindir,
55 "basedir=s",\$basedir,
56 "prebuild",\&prebuild,
57 "kernel-gcc-args=s",\$kernel_gcc_args,
64 my($filename,$optional)=@_;
68 open F,$filename or do { cluck "Open \"$filename\": $!" if !$optional; return ""; };
70 close F or cluck "Close \"$filename\": $!";
76 my($filename,@content)=@_;
79 open F,($filename=~/^[|]/ ? "" : ">").$filename or confess "rewrite \"$filename\": $!";
81 close F or confess "close \"$filename\": $!"; # Do not &cluck as it may be pipe result
88 print STDERR "+ ".join(" ",@args)."\n" if !$quiet;
98 do { ($modproberc=_system $_) and cluck "$_ failed - ignoring"; }
99 for ("/sbin/depmod -aq","/sbin/modprobe lufs");
101 exit ($modproberc ? 1 : 0) if !$lufsmnt_bin;
102 do { exec $lufsmnt_bin,@ARGV; };
103 confess "Failed to exec '$lufsmnt_bin': $!";
107 my $filesystems=_readfile "/proc/filesystems"; # 'lufs' may be built-in
108 _pass if $filesystems=~/\blufs$/m;
109 my $modules=_readfile "/proc/modules"; # 'lufs' may be already loaded
110 _pass if $modules=~/^lufs\b/m;
111 _pass if !_system "/sbin/modprobe lufs 2>/dev/null";
113 my $proc_version=_readfile "/proc/version";
114 my $uname_r=($proc_version=~/^Linux version (\S+)/)[0] || _readfile "uname -r|";
116 confess "Failed to detect kernel version" if !$uname_r;
117 my $uname_smp=($uname_r=~s/smp$// && "smp");
118 my $uname_r_base=($uname_r=~/^([^-]+)/)[0];
119 print STDERR "Running kernel version: $uname_r (base version $uname_r_base)\n" if !$quiet;
121 my $moduledir="/lib/modules/$uname_r$uname_smp/kernel/fs/lufs";
122 print STDERR "Destination module directory: $moduledir\n" if !$quiet;
125 "/lib/modules/$uname_r/build",
126 "/usr/src/kernel-headers-$uname_r",
127 "/usr/src/linux-$uname_r",
128 "/usr/src/linux-$uname_r_base",
131 do { $kernel||=$_ if -d $_; } for (@kernel_paths);
133 print STDERR "Failed to find kernel headers for $uname_r\n" if !$kernel && !$quiet;
136 # We need /usr/include/lufs/* for standard package compilation.
137 # There is no sense to make separate 'devel' package.
138 for ("$vardir/lufs.o") {
140 # Create the 'lufs.o' in our /var/lib directory and only link it
141 # to prevent using obsolete modules after upgrading 'lufs' package.
142 # depmod(1) will take the larget symlink name - we must create directory for it.
143 if (build($kernel,$uname_r,$_)) {
144 do { cluck "Failed to symlink $_"; next; }
145 if _system "/bin/rm -rf $moduledir; /bin/mkdir -p $moduledir; /bin/ln -s $_ $moduledir/lufs.o";
152 for (<$modbindir/*-$uname_r*/*.o>,<$modbindir/*-${uname_r_base}*/*.o>,<$modbindir/*/*.o>) {
153 next if _system "/sbin/rmmod lufs 2>/dev/null; /sbin/insmod -o lufs -p $_ 2>/dev/null";
154 do { cluck "Failed to symlink $_"; next; }
155 if _system "/bin/rm -rf $moduledir; /bin/mkdir -p $moduledir; /bin/ln -s $_ $moduledir/lufs.o";
158 confess "lufs module not loaded: Try running $basedir/prepmod to see more." if $quiet;
159 confess "Failed to prepare lufs.o module for your Linux kernel $uname_r.\n"
160 .($kernel ? "Detected Linux kernel sources \"$kernel\" do not appear to be valid.\n"
161 : "No Linux kernel sources for your running kernel were found.\n")
162 ."Please install kernel-source-x.y.z.i386.rpm or kernel-headers_x.y.z_i386.deb.\n"
163 ."The following directory paths were search (first existing directory used):\n"
164 .join("",map("\t\t$_\n",@kernel_paths));
169 my($kernel,$uname_r,$destmodule)=@_;
171 print STDERR "Using kernel sources: $kernel\n" if !$quiet;
172 confess "Kernel sources $kernel do not contain 'include' subdirectory" if ! -d $kernel."/include";
175 do { $kdebug=$_ if !/^@/; } for ('@KDEBUG_FLAGS@');
176 my $cmdline="/usr/bin/gcc"
177 .($quiet ? " 2>/dev/null" : "")
178 ." -Wall -Wstrict-prototypes -Wno-trigraphs"
179 ." -O2 -fno-strict-aliasing -fno-common -fomit-frame-pointer -pipe -mpreferred-stack-boundary=2"
181 ." -D__KERNEL__ -DMODULE -DLINUX -DKBUILD_MODNAME=lufs"
183 ." ".$kernel_gcc_args
184 ." -I$kernel/include"
185 ." -I$kernel/include/asm-i386/mach-default"; # gcc should not care if this 2.5 dir does not exist
187 my $config=_readfile "$kernel/.config","optional";
188 my $autoconf=_readfile "$kernel/include/linux/autoconf.h","optional";
189 $cmdline.=" -DMODVERSIONS -include $kernel/include/linux/version.h -include $kernel/include/linux/modversions.h"
191 || $config=~/^CONFIG_MODVERSIONS=y\b/m
192 || $autoconf=~/^#define CONFIG_MODVERSIONS\b/m
193 || (!$config && !$autoconf); # assume modversions if not known
195 my @objects=map({ my $o=$_; $o=~s/[.]c$/.o/; $o; } @sources);
196 return !_system "set -e; /bin/mkdir -p `dirname $destmodule`; /bin/rm -f $destmodule;"
197 .(!$vardir ? "" : " cd $vardir;")
198 ." $cmdline -c ".join(" ",map({ srcdir($uname_r)."/".$_; } @sources)).";"
199 ." /usr/bin/ld -r -o $destmodule ".join(" ",@objects).";"
200 ." /bin/rm -f ".join(" ",@objects);
206 my($kernel,$uname_r,$destmodule,%args)=@_;
208 print STDERR "Using kernel sources: $kernel\n" if !$quiet;
209 confess "Kernel sources $kernel do not contain 'Rules.make' file" if ! -f $kernel."/Rules.make";
212 do { $kdebug=$_ if !/^@/; } for ('@KDEBUG_FLAGS@');
213 my $predir=srcdir $uname_r;
214 $predir=$ENV{"PWD"}."/$predir" if $predir!~m#^/#;
215 # Do not use existing '$kernel/tmp_include_depends' or '$kernel/.depend'
216 # as it may contain non-existing pathnames:
217 _system "make -C $kernel dep" if !$args{"nodep"};
218 # Workaround a bug in at least Red Hat 2.4.18-18.8.0
219 for ("$kernel/include/linux/modversions.h") {
220 _system "cp -p $_ $_-orig" if ! -f "$_-orig";
221 _writefile $_,"#include <linux/version.h>\t/* lufs */\n"._readfile $_;
223 my $cmdline="make -C $kernel"
224 ." SUBDIRS=\"$predir\" modules"
225 ." EXTRA_CFLAGS=\"$kernel_gcc_args\""
226 .($quiet ? ' &>/dev/null' : '');
227 my @objects=map({ my $o=$_; $o=~s/[.]c$/.o/; $o; } @sources);
228 return !_system "set -e; /bin/mkdir -p `dirname $destmodule`; /bin/rm -f $destmodule;"
230 ." /bin/rm -f ".join(" ",map(("$predir/$_","$predir/.$_.flags"),@objects)).";"
231 ." /bin/mv -f $predir/lufs.o $destmodule;";
237 my($kernel,$uname_r,$destmodule,%args)=@_;
239 # Debian uname(1) does not support '-p'.
240 my $arch=_readfile "uname -p|" || _readfile "uname -m|";
242 my $single_config=-f "$kernel/.config";
243 if (!$single_config) {
244 my $spec_config="$kernel/configs/kernel-$uname_r_base-$arch".($uname_smp ? "-smp" : "").".config";
245 _system "ln -s $spec_config $kernel/.config"
249 if (-f "$kernel/Rules.make" && -f "$kernel/.config")
250 { $r=build_make $kernel,$uname_r,$destmodule,%args; }
252 { $r=build_gcc $kernel,$uname_r,$destmodule,%args; }
253 _system "rm -f $kernel/.config"
261 my($dir,$vendor,$uname_r,%args)=@_;
263 confess "Unrecognized vendor for dir: $dir" if !$vendor;
264 confess "Unrecognized uname_r for dir: $dir" if !$uname_r;
265 confess "Failed to build $dir" if !build $dir,$uname_r,$modbindir."/lufs-$vendor-$uname_r.o",%args;
273 my $vendor=_readfile "rpm 2>/dev/null --qf '%{VENDOR}' -qp '$rpm' |";
277 $uname_r||=($rpm=~m#/kernel-source-([^-]+-[^-]+)[.][^.]+[.]rpm$#)[0];
278 my $uname_r_base=($uname_r=~/^([^-]+)/)[0];
280 do { $dir||=$_ if -d $_; } for ("/usr/src/linux-$uname_r");
281 do { $dir||=$_ if -d $_; } for ("/usr/src/linux-$uname_r_base"); # older RedHat kernels
282 confess "Kernel sources already found in $dir" if $dir;
283 # '--nodeps' to prevent: error: Failed dependencies: perl-base is needed by *mdk
284 _system "rpm -i --nodeps '$rpm'" and confess "RPM installation of $rpm";
285 do { $dir||=$_ if -d $_; } for ("/usr/src/linux-$uname_r");
286 do { $dir||=$_ if -d $_; } for ("/usr/src/linux-$uname_r_base"); # older RedHat kernels
287 $dir or confess "Kernel source tree not found in: $rpm";
288 _system "cp -p $dir/include/linux/rhconfig.h $dir/include/linux/rhconfig.h-orig"
289 if -f "$dir/include/linux/rhconfig.h";
290 # Do not use existing '$dir/tmp_include_depends' or '$dir/.depend'
291 # as it may contain non-existing pathnames:
292 _system "make -C $dir dep";
293 for my $smp ("","smp") {
294 my @archs=qw(i386 i586 i686 athlon);
295 for my $arch (@archs) {
297 "__BOOT_KERNEL_SMP"=>$smp,
298 map({ ("__MODULE_KERNEL_$_"=>($arch eq $_)); } @archs),
299 "__BOOT_KERNEL_BOOT"=>0,
300 "__BOOT_KERNEL_BOOTSMP"=>0,
301 "__BOOT_KERNEL_ENTERPRISE"=>0,
302 "__BOOT_KERNEL_BIGMEM"=>0,
303 "__BOOT_KERNEL_DEBUG"=>0,
305 if (-f "$dir/include/linux/rhconfig.h") {
308 $defines.="+#define $_ ".($boot{$_} ? 1 : 0)."\n";
310 _system "cp -p -f $dir/include/linux/rhconfig.h-orig $dir/include/linux/rhconfig.h";
311 _writefile "| patch $dir/include/linux/rhconfig.h",<<"RHCONFIG_H_NOBOOT_EOF";
312 --- ./include/linux/rhconfig.h-orig Thu Aug 21 14:50:16 2003
313 +++ ./include/linux/rhconfig.h Thu Aug 21 14:59:22 2003
314 \@\@ -10,7 +10,@{[ 7+keys(%boot) ]} \@\@
315 * /boot/kernel.h - initscripts should create it for us
318 -#include "/boot/kernel.h"
319 +/* lufs: #include "/boot/kernel.h" */
321 #if defined(__BOOT_KERNEL_SMP) && (__BOOT_KERNEL_SMP == 1)
322 #define __module__smp
323 RHCONFIG_H_NOBOOT_EOF
325 # Mandrake packages have no configs/ and they have just that '.config' file.
326 my $single_config=-f "$dir/.config";
327 if (!$single_config) {
328 my $spec_config="$dir/configs/kernel-$uname_r_base-$arch".($smp ? "-smp" : "").".config";
329 next if ! -f $spec_config;
330 _system "ln -s $spec_config $dir/.config";
332 prebuild_kernel $dir,$vendor,$uname_r.$smp.".".$arch,"nodep"=>1;
333 _system "rm -f $dir/.config"
337 _system "rpm -e kernel-source-$uname_r" and confess "Remove of kernel-source-$uname_r";
338 _system "rm -rf $dir";
346 chomp (my $debian=_readfile "/etc/debian_version","optional");
348 $vendor="Debian".$debian if $debian && $dir=~m#^/usr/src/#;
350 $uname_r||=($dir=~m#/kernel-headers-([^/]+)/*$#)[0];
351 $uname_r||=($dir=~m#/linux-([^/]+)/*$#)[0];
352 $uname_r||=($dir=~m#^/lib/modules/([^/]+)/build/*$#)[0];
353 prebuild_kernel $dir,$vendor,$uname_r;
358 $vardir=undef(); # we may not yet have /var/lib/lufs
360 do { prebuild_rpm $_; next; } if /[.]rpm$/;
361 do { prebuild_dir $_; next; } if -d $_;
362 confess "Unrecognized kernel: $_";