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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
#!/usr/bin/env python
#
# Kernel.py: this file is part of the GRS suite
# Copyright (C) 2015 Anthony G. Basile
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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')
self.busybox_config = os.path.join(self.libdir, 'scripts/busybox-config')
self.genkernel_config = os.path.join(self.libdir, 'scripts/genkernel.conf')
def parse_kernel_config(self):
""" Parse the version to be built/installed from the kernel-config file. """
with open(self.kernel_config, 'r') as _file:
lines = _file.readlines()
# Are we building a modular kernel or statically linked?
has_modules = 'CONFIG_MODULES=y\n' in lines
# The third line is the version line in the kernel config file.
version_line = lines[2]
# The version line looks like the following:
# Linux/x86 4.0.6-hardened-r2 Kernel Configuration
# The 2nd group contains the version.
_match = re.search(r'^#\s+(\S+)\s+(\S+).+$', version_line)
gentoo_version = _match.group(2)
try:
# Either the verison is of the form '4.0.6-hardened-r2' with two -'s
_match = re.search(r'(\S+?)-(\S+?)-(\S+)', gentoo_version)
vanilla_version = _match.group(1)
flavor = _match.group(2)
revision = _match.group(3)
pkg_name = flavor + '-sources-' + vanilla_version + '-' + revision
except AttributeError:
# Or the verison is of the form '4.0.6-hardened' with one -
try:
_match = re.search(r'(\S+?)-(\S+)', gentoo_version)
vanilla_version = _match.group(1)
flavor = _match.group(2)
pkg_name = flavor + '-sources-' + vanilla_version
except AttributeError:
# Finally the verison is of the form '4.0.6' with no -
vanilla_version = gentoo_version
pkg_name = 'vanilla-sources-' + vanilla_version
pkg_name = '=sys-kernel/' + pkg_name
return (gentoo_version, pkg_name, has_modules)
def kernel(self, arch='x86_64'):
""" 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, has_modules) = 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')
modules_dir = os.path.join(image_dir, 'lib/modules')
# The firmware directory, if it exists, will be in self.portage_configroot
firmware_dir = os.path.join(self.portage_configroot, 'lib/firmware')
# Prepare tarball filename and path. If the tarball already exists,
# don't rebuild/reinstall it. Note: It should have been installed to
# the system's portage configroot when it was first built, so no need
# to reinstall it.
linux_images = os.path.join(self.package, 'linux-images')
tarball_name = 'linux-image-%s.tar.xz' % gentoo_version
tarball_path = os.path.join(linux_images, tarball_name)
if os.path.isfile(tarball_path):
return
# 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.
# NOTE: more options (eg splash and firmware), can be specified
# via the kernel line in the build script.
cmd = 'genkernel '
cmd += '--logfile=/dev/null '
cmd += '--no-save-config '
cmd += '--makeopts=-j9 '
cmd += '--symlink '
cmd += '--no-mountboot '
cmd += '--kernel-config=%s ' % self.kernel_config
cmd += '--kerneldir=%s ' % kernel_source
cmd += '--bootdir=%s ' % boot_dir
cmd += '--kernel-modules-prefix=%s ' % image_dir
cmd += '--modprobedir=%s ' % modprobe_dir
if os.path.isfile(self.busybox_config):
cmd += '--busybox-config=%s ' % self.busybox_config
if os.path.isfile(self.genkernel_config):
cmd += '--config=%s ' % self.genkernel_config
if os.path.isdir(firmware_dir):
cmd += '--firmware-dir=%s ' % firmware_dir
if has_modules:
cmd += 'all'
else:
cmd += 'bzImage'
Execute(cmd, timeout=None, logfile=self.logfile)
# Strip the modules to shrink their size enormously!
# This will do nothing if there is not modules_dir
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 -aK %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
os.makedirs(linux_images, mode=0o755, exist_ok=True)
cwd = os.getcwd()
os.chdir(image_dir)
cmd = 'tar -Jcf %s .' % tarball_path
Execute(cmd, timeout=600, logfile=self.logfile)
os.chdir(cwd)
|