aboutsummaryrefslogtreecommitdiff
blob: c9a99d80d8bffc5b009cdfeee61f49486656aaed (plain)
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
#!/usr/bin/env python

import os
import re
import shutil

from grs.Constants import CONST
from grs.Execute import Execute


class Kernel():
    """ Build a linux-image pkg and install when building a system. """

    def __init__(self, libdir = CONST.LIBDIR, portage_configroot = CONST.PORTAGE_CONFIGROOT, \
            kernelroot = CONST.KERNELROOT, package = CONST.PACKAGE, logfile = CONST.LOGFILE):
        self.libdir = libdir
        self.portage_configroot = portage_configroot
        self.kernelroot = kernelroot
        self.package = package
        self.logfile = logfile
        self.kernel_config = os.path.join(self.libdir, 'scripts/kernel-config')


    def parse_kernel_config(self):
        """ Parse the version to be built/installed from the kernel-config file. """
        with open(self.kernel_config, 'r') as f:
            for i in range(3):
                line = f.readline()
        # The version line looks like the following:
        # Linux/x86 4.0.6-hardened-r2 Kernel Configuration
        # The 2nd group contains the version.
        m = re.search('^#\s+(\S+)\s+(\S+).+$', line)
        gentoo_version = m.group(2)
        try:
            # Either the verison is of the form '4.0.6-hardened-r2' with two -'s
            m = re.search('(\S+?)-(\S+?)-(\S+)', gentoo_version)
            vanilla_version = m.group(1)
            flavor = m.group(2)
            revision = m.group(3)
            pkg_name = flavor + '-sources-' + vanilla_version + '-' + revision
        except AttributeError:
            # Or the verison is of the form '4.0.6-hardened' with one -
            m = re.search('(\S+?)-(\S+)', gentoo_version)
            vanilla_version = m.group(1)
            flavor = m.group(2)
            pkg_name = flavor + '-sources-' + vanilla_version
        pkg_name = '=sys-kernel/' + pkg_name
        return (gentoo_version, pkg_name)


    def kernel(self):
        """ This emerges the kernel sources to a directory outside of the
            fledgeling system's portage configroot, builds and installs it
            to yet another external directory, bundles the kernel and modules
            as a .tar.xz in the packages directory for downloads via grsup,
            and finally installs it to the system's portage configroot.
        """
        # Grab the parsed verison and pkg atom.
        (gentoo_version, pkg_name) = self.parse_kernel_config()

        # Prepare the paths to where we'll emerge and build the kernel,
        # as well as paths for genkernel.
        kernel_source = os.path.join(self.kernelroot, 'usr/src/linux')
        image_dir     = os.path.join(self.kernelroot, gentoo_version)
        boot_dir      = os.path.join(image_dir, 'boot')
        modprobe_dir  = os.path.join(image_dir, 'etc/modprobe.d')
        # TODO: modules_dir really needs $(get_libdir), eg /lib64.
        # For example, this breaks on amd64 multilib.
        modules_dir   = os.path.join(image_dir, 'lib/modules')

        # Remove any old kernel image directory and create a boot directory.
        # Note genkernel assumes a boot directory is present.
        shutil.rmtree(image_dir, ignore_errors=True)
        os.makedirs(boot_dir, mode=0o755, exist_ok=True)

        # emerge the kernel source.
        cmd = 'emerge --nodeps -1n %s' % pkg_name
        emerge_env = { 'USE' : 'symlink', 'ROOT' : self.kernelroot, 'ACCEPT_KEYWORDS' : '**' }
        Execute(cmd, timeout=600, extra_env=emerge_env, logfile=self.logfile)

        # Build and install the image outside the portage configroot so
        # we can both rsync it in *and* tarball it for downloads via grsup.
        # TODO: add more options (eg splash and firmware), which can be
        # specified vi the kernel line in the build script.
        cmd = 'genkernel '
        cmd += '--logfile=/dev/null '
        cmd += '--no-save-config '
        cmd += '--makeopts=-j9 '
        cmd += '--no-firmware '
        cmd += '--symlink '
        cmd += '--no-mountboot '
        cmd += '--kernel-config=%s ' % self.kernel_config
        cmd += '--kerneldir=%s '     % kernel_source
        cmd += '--bootdir=%s '       % boot_dir
        cmd += '--module-prefix=%s ' % image_dir
        cmd += '--modprobedir=%s '   % modprobe_dir
        cmd += 'all'
        Execute(cmd, timeout=None, logfile=self.logfile)

        # Strip the modules to shrink their size enormously!
        for dirpath, dirnames, filenames in os.walk(modules_dir):
            for filename in filenames:
                if filename.endswith('.ko'):
                    module = os.path.join(dirpath, filename)
                    cmd = 'objcopy -v --strip-unneeded %s' % module
                    Execute(cmd)

        # Copy the newly compiled kernel image and modules to portage configroot
        cmd = 'rsync -a %s/ %s' % (image_dir, self.portage_configroot)
        Execute(cmd, timeout=60, logfile=self.logfile)

        # Tar up the kernel image and modules and place them in package/linux-images
        linux_images = os.path.join(self.package, 'linux-images')
        os.makedirs(linux_images, mode=0o755, exist_ok=True)
        tarball_name = 'linux-image-%s.tar.xz' % gentoo_version
        tarball_path = os.path.join(linux_images, tarball_name)

        cwd = os.getcwd()
        os.chdir(image_dir)
        if os.path.isfile(tarball_path):
            os.unlink(tarball_path)
        cmd = 'tar -Jcf %s .' % tarball_path
        Execute(cmd, timeout=600, logfile=self.logfile)
        os.chdir(cwd)