Always rebuild Linux kernel dependencies as the shipped one may be broken.
[lufs.git] / kernel / Linux / prepmod.in
index 48f4114..5f67cb5 100755 (executable)
@@ -27,23 +27,29 @@ use Getopt::Long;
 
 my $basedir='@datadir@/lufs';
 my $vardir='@localstatedir@/lib/lufs';
+my $includedir='@includedir@'; # '/lufs' is required by C '#include'
 $basedir=~s#\$\Q{prefix}\E#'@prefix@';#ge;
 $vardir=~s#\$\Q{prefix}\E#'@prefix@';#ge;
 $vardir="" if $vardir=~/^@/;
+$includedir=~s#\$\Q{prefix}\E#'@prefix@';#ge;
+$includedir="" if $includedir=~/^@/;
 sub srcdir { my($uname_r)=@_; $basedir."/".($uname_r lt "2.5" ? "2.4" : "2.5"); }
 my $modbindir=$basedir."/modbin";
 my @sources=qw(proc.c inode.c dir.c file.c symlink.c);
-my $tmp_dir="prepmod-tmp-dir";
 
 my $quiet;
 my $kernel;
 my $prebuild;
-my $kernel_gcc_args="";
+use vars qw($kernel_gcc_args);
+$kernel_gcc_args="";
+$kernel_gcc_args="-I$includedir" if $includedir;
 
 my $lufsmnt_bin;
 if ($0 eq "lufsmnt" || $0=~m#/lufsmnt$#) {
        $quiet=1;
        $lufsmnt_bin='@bindir@/lufsmnt-bin';
+       $lufsmnt_bin=~s#\$\Q{exec_prefix}\E#'@exec_prefix@';#ge;
+       $lufsmnt_bin=~s#\$\Q{prefix}\E#'@prefix@';#ge;
        }
 else {
        die if !GetOptions(
@@ -69,6 +75,16 @@ my($filename,$optional)=@_;
        return $r;
 }
 
+sub _writefile
+{
+my($filename,@content)=@_;
+
+       local *F;
+       open F,($filename=~/^[|]/ ? "" : ">").$filename or confess "rewrite \"$filename\": $!";
+       print F @content;
+       close F or confess "close \"$filename\": $!";   # Do not &cluck as it may be pipe result
+}
+
 sub _system
 {
 my(@args)=@_;
@@ -83,7 +99,8 @@ my($load)=@_;
 
        my $modproberc;
        if ($load) {
-               do { ($modproberc=_system $_) and cluck "$_ failed - ignoring"; } for ("depmod -aq","modprobe lufs");
+               do { ($modproberc=_system $_) and cluck "$_ failed - ignoring"; }
+                               for ("/sbin/depmod -aq","/sbin/modprobe lufs");
                }
        exit ($modproberc ? 1 : 0) if !$lufsmnt_bin;
        do { exec $lufsmnt_bin,@ARGV; };
@@ -95,47 +112,54 @@ my $filesystems=_readfile "/proc/filesystems";     # 'lufs' may be built-in
 _pass if $filesystems=~/\blufs$/m;
 my $modules=_readfile "/proc/modules"; # 'lufs' may be already loaded
 _pass if $modules=~/^lufs\b/m;
-_pass if !_system "modprobe lufs 2>/dev/null";
+_pass if !_system "/sbin/modprobe lufs 2>/dev/null";
 
 my $proc_version=_readfile "/proc/version";
 my $uname_r=($proc_version=~/^Linux version (\S+)/)[0] || _readfile "uname -r|";
 chomp $uname_r;
 confess "Failed to detect kernel version" if !$uname_r;
+my $uname_smp=($uname_r=~s/smp$// && "smp");
 my $uname_r_base=($uname_r=~/^([^-]+)/)[0];
 print STDERR "Running kernel version: $uname_r (base version $uname_r_base)\n" if !$quiet;
 
+my $moduledir="/lib/modules/$uname_r$uname_smp/kernel/fs/lufs";
+print STDERR "Destination module directory: $moduledir\n" if !$quiet;
+
 do { $kernel||=$_ if -d $_; } for ("/lib/modules/$uname_r/build");
 do { $kernel||=$_ if -d $_; } for ("/usr/src/kernel-headers-$uname_r");
 do { $kernel||=$_ if -d $_; } for ("/usr/src/linux-$uname_r");
 do { $kernel||=$_ if -d $_; } for ("/usr/src/linux-$uname_r_base");
 do { $kernel||=$_ if -d $_; } for ("/usr/src/linux");
-confess "Failed to find kernel headers for $uname_r" if !$kernel;
-
-my $moduledir="/lib/modules/$uname_r/kernel/fs/lufs";
-print STDERR "Destination module directory: $moduledir\n" if !$quiet;
-
-for ("$vardir/lufs.o") {
-       next if !$vardir;
-       # Create the 'lufs.o' in our /var/lib directory and only link it
-       # to prevent using obsolete modules after upgrading 'lufs' package.
-       # depmod(1) will take the larget symlink name - we must create directory for  it.
-       if (build($kernel,$uname_r,$_)) {
-               do { cluck "Failed to symlink $_"; next; }
-                               if _system "rm -rf $moduledir; mkdir -p $moduledir; ln -s $_ $moduledir/lufs.o";
-               _pass 1;
+if (!$kernel) {
+       print STDERR "Failed to find kernel headers for $uname_r\n" if !$kernel && !$quiet;
+       }
+else {
+       # We need /usr/include/lufs/* for standard package compilation.
+       # There is no sense to make separate 'devel' package.
+       for ("$vardir/lufs.o") {
+               next if !$vardir;
+               # Create the 'lufs.o' in our /var/lib directory and only link it
+               # to prevent using obsolete modules after upgrading 'lufs' package.
+               # depmod(1) will take the larget symlink name - we must create directory for  it.
+               if (build($kernel,$uname_r,$_)) {
+                       do { cluck "Failed to symlink $_"; next; }
+                                       if _system "/bin/rm -rf $moduledir; /bin/mkdir -p $moduledir; /bin/ln -s $_ $moduledir/lufs.o";
+                       _pass 1;
+                       }
                }
        }
 
 local $_;
-for (<$modbindir/*-$uname_r.o>,<$modbindir/*-${uname_r_base}*.o>,<$modbindir/*.o>) {
-       next if _system "rmmod lufs 2>/dev/null; insmod -o lufs -p $_ 2>/dev/null";
-       do { cluck "Failed to symlink $_"; next; } if _system "mkdir -p $moduledir; ln -s $_ $moduledir/lufs.o";
+for (<$modbindir/*-$uname_r*/*.o>,<$modbindir/*-${uname_r_base}*/*.o>,<$modbindir/*/*.o>) {
+       next if _system "/sbin/rmmod lufs 2>/dev/null; /sbin/insmod -o lufs -p $_ 2>/dev/null";
+       do { cluck "Failed to symlink $_"; next; }
+                       if _system "/bin/rm -rf $moduledir; /bin/mkdir -p $moduledir; /bin/ln -s $_ $moduledir/lufs.o";
        _pass 1;
        }
-confess "lufs module not loaded: $basedir not compilable and no module of $modbindir/*.o usable";
+confess "lufs module not loaded: Try running $basedir/prepmod to see more.";
 
 
-sub build
+sub build_gcc
 {
 my($kernel,$uname_r,$destmodule)=@_;
 
@@ -144,9 +168,11 @@ my($kernel,$uname_r,$destmodule)=@_;
 
        my $kdebug="";
        do { $kdebug=$_ if !/^@/; } for ('@KDEBUG_FLAGS@');
-       my $cmdline="gcc"
+       my $cmdline="/usr/bin/gcc"
                        .($quiet ? " 2>/dev/null" : "")
-                       ." -O2 -pipe -fomit-frame-pointer -fno-strict-aliasing -mpreferred-stack-boundary=2 -Wall"
+                       ." -Wall -Wstrict-prototypes -Wno-trigraphs"
+                       ." -O2 -fno-strict-aliasing -fno-common -fomit-frame-pointer -pipe -mpreferred-stack-boundary=2"
+                       #." -march=i586"
                        ." -D__KERNEL__ -DMODULE -DLINUX -DKBUILD_MODNAME=lufs"
                        ." ".$kdebug
                        ." ".$kernel_gcc_args
@@ -162,11 +188,58 @@ my($kernel,$uname_r,$destmodule)=@_;
                                        || (!$config && !$autoconf);    # assume modversions if not known
 
        my @objects=map({ my $o=$_; $o=~s/[.]c$/.o/; $o; } @sources);
-       return !_system "set -e; mkdir -p `dirname $destmodule`; rm -f $destmodule;"
+       return !_system "set -e; /bin/mkdir -p `dirname $destmodule`; /bin/rm -f $destmodule;"
                        .(!$vardir ? "" : " cd $vardir;")
                        ." $cmdline -c ".join(" ",map({ srcdir($uname_r)."/".$_; } @sources)).";"
-                       ." ld -r -o $destmodule ".join(" ",@objects).";"
-                       ." rm -f ".join(" ",@objects);
+                       ." /usr/bin/ld -r -o $destmodule ".join(" ",@objects).";"
+                       ." /bin/rm -f ".join(" ",@objects);
+}
+
+
+sub build_make
+{
+my($kernel,$uname_r,$destmodule)=@_;
+
+       print STDERR "Using kernel sources: $kernel\n" if !$quiet;
+       confess "Kernel sources $kernel do not contain 'Rules.make' file" if ! -f $kernel."/Rules.make";
+
+       my $kdebug="";
+       do { $kdebug=$_ if !/^@/; } for ('@KDEBUG_FLAGS@');
+       my $predir=srcdir $uname_r;
+       $predir=$ENV{"PWD"}."/$predir" if $predir!~m#^/#;
+       my $cmdline="make -C $kernel"
+                       ." SUBDIRS=\"$predir\" modules"
+                       ." EXTRA_CFLAGS=\"$kernel_gcc_args\""
+                       .($quiet ? ' &>/dev/null' : '');
+       my @objects=map({ my $o=$_; $o=~s/[.]c$/.o/; $o; } @sources);
+       return !_system "set -e; /bin/mkdir -p `dirname $destmodule`; /bin/rm -f $destmodule;"
+                       ." $cmdline;"
+                       ." /bin/rm -f ".join(" ",map(("$predir/$_","$predir/.$_.flags"),@objects)).";"
+                       ." /bin/mv -f $predir/lufs.o $destmodule;";
+}
+
+
+sub build
+{
+my($kernel,$uname_r,$destmodule)=@_;
+
+       # Debian uname(1) does not support '-p'.
+       my $arch=_readfile "uname -p|" || _readfile "uname -m|";
+       chomp $arch;
+       my $single_config=-f "$kernel/.config";
+       if (!$single_config) {
+               my $spec_config="$kernel/configs/kernel-$uname_r_base-$arch".($uname_smp ? "-smp" : "").".config";
+               _system "ln -s $spec_config $kernel/.config"
+                               if -f $spec_config;
+               }
+       my $r;
+       if (-f "$kernel/Rules.make" && -f "$kernel/.config")
+               { $r=build_make $kernel,$uname_r,$destmodule; }
+       else
+               { $r=build_gcc $kernel,$uname_r,$destmodule; }
+       _system "rm -f $kernel/.config"
+                       if !$single_config;
+       return $r;
 }
 
 
@@ -189,12 +262,67 @@ my($rpm)=@_;
        $vendor=~tr/ //d;
        my $uname_r;
        $uname_r||=($rpm=~m#/kernel-source-([^-]+-[^-]+)[.][^.]+[.]rpm$#)[0];
-       _system "rm -rf $tmp_dir; mkdir $tmp_dir; set -e;"
-                       # Here we will extract even some false 'include's but we filter dirs just for speed/space.
-                       ." rpm2cpio '$rpm' | (cd $tmp_dir; cpio -id --quiet ./usr/src/linux*/{.config,include/*})"
-                       and confess "Extraction of: $rpm";
-       prebuild_kernel $tmp_dir."/usr/src/linux-$uname_r",$vendor,$uname_r;
-       _system "rm -rf $tmp_dir" and confess "Deletion of: $tmp_dir";
+       my $uname_r_base=($uname_r=~/^([^-]+)/)[0];
+       my $dir;
+       do { $dir||=$_ if -d $_; } for ("/usr/src/linux-$uname_r");
+       do { $dir||=$_ if -d $_; } for ("/usr/src/linux-$uname_r_base");        # older RedHat kernels
+       confess "Kernel sources already found in $dir" if $dir;
+       # '--nodeps' to prevent: error: Failed dependencies: perl-base is needed by *mdk
+       _system "rpm -i --nodeps '$rpm'" and confess "RPM installation of $rpm";
+       do { $dir||=$_ if -d $_; } for ("/usr/src/linux-$uname_r");
+       do { $dir||=$_ if -d $_; } for ("/usr/src/linux-$uname_r_base");        # older RedHat kernels
+       $dir or confess "Kernel source tree not found in: $rpm";
+       _system "cp -p $dir/include/linux/rhconfig.h $dir/include/linux/rhconfig.h-orig"
+                               if -f "$dir/include/linux/rhconfig.h";
+       # Do not use existing '$dir/tmp_include_depends' or '$dir/.depend'
+       # as it may contain non-existing pathnames:
+       _system "make -C $dir dep";
+       for my $smp ("","smp") {
+               my @archs=qw(i386 i586 i686 athlon);
+               for my $arch (@archs) {
+                       my %boot=(
+                                       "__BOOT_KERNEL_SMP"=>$smp,
+                                       map({ ("__MODULE_KERNEL_$_"=>($arch eq $_)); } @archs),
+                                       "__BOOT_KERNEL_BOOT"=>0,
+                                       "__BOOT_KERNEL_BOOTSMP"=>0,
+                                       "__BOOT_KERNEL_ENTERPRISE"=>0,
+                                       "__BOOT_KERNEL_BIGMEM"=>0,
+                                       "__BOOT_KERNEL_DEBUG"=>0,
+                                       );
+                       if (-f "$dir/include/linux/rhconfig.h") {
+                               my $defines="";
+                               for (keys(%boot)) {
+                                       $defines.="+#define $_ ".($boot{$_} ? 1 : 0)."\n";
+                                       }
+                               _system "cp -p -f $dir/include/linux/rhconfig.h-orig $dir/include/linux/rhconfig.h";
+                               _writefile "| patch $dir/include/linux/rhconfig.h",<<"RHCONFIG_H_NOBOOT_EOF";
+--- ./include/linux/rhconfig.h-orig    Thu Aug 21 14:50:16 2003
++++ ./include/linux/rhconfig.h Thu Aug 21 14:59:22 2003
+\@\@ -10,7 +10,@{[ 7+keys(%boot) ]} \@\@
+  * /boot/kernel.h - initscripts should create it for us
+  */
+-#include "/boot/kernel.h"
++/* lufs: #include "/boot/kernel.h" */
+$defines
+ #if defined(__BOOT_KERNEL_SMP) && (__BOOT_KERNEL_SMP == 1)
+ #define __module__smp
+RHCONFIG_H_NOBOOT_EOF
+                               }
+                       # Mandrake packages have no configs/ and they have just that '.config' file.
+                       my $single_config=-f "$dir/.config";
+                       if (!$single_config) {
+                               my $spec_config="$dir/configs/kernel-$uname_r_base-$arch".($smp ? "-smp" : "").".config";
+                               next if ! -f $spec_config;
+                               _system "ln -s $spec_config $dir/.config";
+                               }
+                       prebuild_kernel $dir,$vendor,$uname_r.$smp.".".$arch;
+                       _system "rm -f $dir/.config"
+                                       if !$single_config;
+                       }
+               }
+       _system "rpm -e kernel-source-$uname_r" and confess "Remove of kernel-source-$uname_r";
+       _system "rm -rf $dir";
 }
 
 sub prebuild_dir
@@ -203,6 +331,7 @@ my($dir)=@_;
 
        my $vendor;
        chomp (my $debian=_readfile "/etc/debian_version","optional");
+       $debian=~tr#/#_#;
        $vendor="Debian".$debian if $debian && $dir=~m#^/usr/src/#;
        my $uname_r;
        $uname_r||=($dir=~m#/kernel-headers-([^/]+)/*$#)[0];