3 # Copyright (C) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
4 # Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
5 # Tim Abbott <tabbott@mit.edu>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License, version 2.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 use lib
'KSPLICE_DATA_DIR';
25 my ($patchfile, $diffext, $orig_config_dir, $jobs, $kid);
30 my ($prebuild, $skip_prebuild) = (0, 0);
31 my @patch_opt = "-p1";
32 GetOptions
(@common_options,
34 "patch=s" => \
$patchfile,
35 "diffext=s" => \
$diffext,
36 "prebuild" => \
$prebuild,
37 "series!" => \
$series,
38 "only-targets=s" => \
@only_targets,
39 "extra-match=s" => \
@extra_match,
40 "standalone!" => \
$standalone,
41 "skip-prebuild" => \
$skip_prebuild,
43 "config=s" => \
$orig_config_dir,
44 "patch-opt=s" => \
@patch_opt) or pod2usage
(1);
46 pod2usage
(1) if($help || scalar(@ARGV) != 1);
47 my $actions = (defined $patchfile) + (defined $diffext) + ($prebuild);
48 pod2usage
(1) if($actions != 1);
50 my ($linuxtree) = (abs_path
($ARGV[0]));
52 if(!defined $orig_config_dir) {
53 $orig_config_dir = "$linuxtree/ksplice";
56 $orig_config_dir = abs_path
($orig_config_dir);
57 if($orig_config_dir =~ $linuxtree) {
58 die "Aborting: User-specified ORIG_CONFIG cannot be KERNEL_SOURCE or a subdirectory";
61 if(!defined $orig_config_dir || ! -d
$orig_config_dir) {
62 die "Failed to find ORIG_CONFIG directory ($orig_config_dir)";
64 if(! -e
"$orig_config_dir/.config") {
65 die "Failed to find .config file in ORIG_CONFIG directory";
67 if(! -e
"$orig_config_dir/System.map") {
68 die "Failed to find System.map file in ORIG_CONFIG directory";
71 my $kernel_headers_dir = "$orig_config_dir/build";
72 $kernel_headers_dir = $linuxtree unless(-d
$kernel_headers_dir);
74 my @kbuild_flags = ();
75 if(-e
"$orig_config_dir/flags") {
76 open(FLAGS
, '<', "$orig_config_dir/flags") or die;
78 @kbuild_flags = shellwords
(scalar <FLAGS
>);
82 $ENV{KSPLICE_VERBOSE
} = $Verbose::level
;
83 $ENV{KSPLICE_CONFIG_DIR
} = $orig_config_dir;
85 my @chars = ('a'..'z', 0..9);
86 $kid = join '', map { $chars[int(rand(36))] } 0..7 if(!defined $kid);
87 my $ksplice = "ksplice-$kid";
88 $ENV{KSPLICE_KID
} = $kid;
90 # Some versions of Fedora have System.map files whose symbol addresses disagree
91 # with the running kernel by a constant address offset. Here, Ksplice notes the
92 # System.map address for printk so that it can later compare this address against
93 # the kernel's address for printk. This comparison helps Ksplice work around
94 # this Fedora problem, and this comparison also helps Ksplice detect whether
95 # the user has provided an incorrect System.map file.
96 my $map_printk = runstr
("$datadir/ksplice-obj.pl", "system_map_lookup", "printk");
98 print "Starting kernel builds (this process might take a long time)...\n"
99 if($Verbose::level
>= 0);
101 $patchfile = abs_path
($patchfile) if(defined $patchfile);
103 my $origdir = getcwd
();
106 my @make = ("make", "-rR");
108 push @make, "-j$jobs";
109 } elsif(defined $ENV{CONCURRENCY_LEVEL
}) {
110 push @make, "-j$ENV{CONCURRENCY_LEVEL}";
113 if($Verbose::level
>= 2) {
115 } elsif($Verbose::level
< 0) {
119 $ENV{PATH
} = "$datadir:$ENV{PATH}";
120 my @make_ksplice = (@make, "-f", "$datadir/Makefile.ksplice", @kbuild_flags);
123 for(split(/\0/, runstr
(qw(find -name *.KSPLICE_* -print0)))) {
124 if(my ($file) = m/^(.*)\.KSPLICE_pre$/) {
130 runval
("$datadir/ksplice-obj.pl", "snap", "$file.KSPLICE") if(-e
"$file.KSPLICE");
131 } elsif(m/\.KSPLICE_(?:primary|helper)$/) {
132 unlink($_) if(-e
$_);
138 if(!$skip_prebuild) {
139 copy
("$orig_config_dir/.config", "$linuxtree/.config");
140 utime((stat("$orig_config_dir/.config"))[8, 9], "$linuxtree/.config");
141 my @snap_flags = ("KSPLICE_MODE=snap");
142 if(-e
"include/config/kernel.release") {
143 push(@snap_flags, "-o", "include/config/kernel.release");
145 runval_raw
(@make_ksplice, @snap_flags) == 0 or
146 die "Aborting: Prebuild failed";
149 exit(0) if($prebuild);
151 my $tmpdir = tempdir
('ksplice-tmp-XXXXXX', TMPDIR
=> 1, CLEANUP
=> 1);
152 copy
($patchfile, "$tmpdir/patch") if(defined $patchfile);
153 $patchfile = "$tmpdir/patch";
155 if(defined $diffext) {
156 open(PATCH
, '>', $patchfile) or die;
157 for(split(/\0/, runstr
("find", "-name", "*$diffext", "-print0"))) {
158 my ($file) = /^(.*)\Q$diffext\E/ or die;
159 print PATCH runstr
("diff", "-u", "--", $file, $_);
162 @patch_opt = ("-p0");
165 my $kmodsrc = "$tmpdir/kmodsrc";
166 runval
("cp", "-a", "--", "$datadir/kmodsrc", $kmodsrc);
167 $ENV{KSPLICE_KMODSRC
} = $kmodsrc;
169 my @make_kmodsrc = (@make, "-C", $kernel_headers_dir, "M=$kmodsrc", "KSPLICE_KID=$kid", "KSPLICE_VERSION=PACKAGE_VERSION", "map_printk=$map_printk");
171 if (!defined($standalone)) {
172 $standalone = (runval_raw
(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
174 push(@make_kmodsrc, "KSPLICE_STANDALONE=1") if ($standalone);
176 runval
(@make_kmodsrc);
178 @patch_opt = ("-s", @patch_opt) if ($Verbose::level
< 0);
180 runval_infile
($patchfile, "patch", @patch_opt, "-bz", ".KSPLICE_pre");
181 push @make_ksplice, "KSPLICE_EXTRA_MATCH=@extra_match" if (@extra_match);
182 push @make_ksplice, "KSPLICE_ONLY_TARGETS=@only_targets" if (@only_targets);
183 if(runval_raw
(@make_ksplice, "KSPLICE_MODE=diff") != 0) {
184 revert_orig
() if(defined($diffext));
185 die "Aborting: Applying the patch appears to break the kernel build";
190 my ($dir, $base) = (dirname
($file), basename
($file));
191 -d
"$tmpdir/objects/$dir" or mkpath
("$tmpdir/objects/$dir");
192 copy
($file, "$tmpdir/objects/$file");
193 my $cmdfile = "$dir/.$base.cmd";
194 copy
($cmdfile, "$tmpdir/objects/$cmdfile") if(-e
$cmdfile);
197 mkdir("$tmpdir/objects");
198 for (split(/\0/, runstr
(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name
.*.KSPLICE
.cmd
-print0
)))) {
200 copy_debug
($1) if (m/^(.*)\.KSPLICE_pre$/);
204 foreach(glob(".tmp_versions/*.mod.KSPLICE")) {
206 chomp(my $mod = <MOD
>);
208 foreach my $collect ("$mod.o.KSPLICE", "$mod.o.KSPLICE_primary",
209 "$mod.o.KSPLICE_helper") {
210 copy
($collect, "$kmodsrc/" . basename
($collect));
212 push @modules, basename
($mod);
216 revert_orig
() if(defined($diffext));
217 die "Aborting: No changes detected";
220 revert_orig
() if(defined($diffext));
222 runval
(@make_kmodsrc, "modules", "KSPLICE_MODULES=@modules");
226 move
($patchfile, $ksplice);
227 foreach my $mod (@modules) {
228 (my $target = $mod) =~ s/-/_/g;
229 my $mid = "${kid}_$target";
230 my $module = "ksplice-$mid";
231 rename("$kmodsrc/$module.ko", "$ksplice/$module.ko");
232 rename("$kmodsrc/$module-helper.ko", "$ksplice/$module-helper.ko");
234 rename("$kmodsrc/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko") if ($standalone);
236 mkdir("$ksplice/debug");
237 rename("objects", "$ksplice/debug/objects");
238 rename("$kmodsrc", "$ksplice/debug/kmodsrc");
239 runval
("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
240 copy
("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
242 print "Ksplice update tarball written to $ksplice.tar.gz\n";
247 ksplice-create - Create a set of kernel modules for a rebootless kernel update
251 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
253 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
255 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
259 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
260 will apply a user-specified source code patch to the running binary kernel.
262 Before you use B<ksplice-create> on a patch, you should confirm that the
263 desired source code change does not make any semantic changes to kernel data
264 structures--that is, changes that would require existing instances of kernel
265 data structures to be transformed (e.g., a patch that adds a field to a global
266 data structure would require the existing data structures to change). If you
267 use Ksplice on a patch that changes data structure semantics, Ksplice will not
268 detect the problem and you could experience kernel problems as a result.
270 The to-be-applied source code patch can be specified by providing a L<patch(1)>
271 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
272 (B<--diffext=>I<EXTENSION>).
274 If a file extension is specified, then the desired source code patch will be
275 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
276 whose names end with the extra extension I<EXTENSION> against the corresponding
277 files without the extra extension. Only the new files containing the extra
278 extension in their filenames should be modified.
280 Here is an example of using a file extension to specify a patch:
282 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
283 [edit sys.c.prctl_fixed to include the desired changes]
284 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
286 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
287 original source code. If your Linux distribution applies patches to the Linux
288 kernel during the kernel build process, then those patches must be applied to
289 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
290 directory. B<ksplice-create> will not modify the source code in the
291 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
294 I<ORIG_CONFIG> can be used to specify the directory containing the
295 to-be-updated kernel's original F<.config> file and original F<System.map> file
296 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
297 I<KERNEL_SOURCE>B</ksplice>.
299 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
300 close to the compiler and assembler originally used to build the running kernel
301 as possible. If the current compiler and linker are too different from the
302 original compiler and linker, B<ksplice-apply> will abort when applying the
305 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
306 containing the desired Ksplice update modules. This tarball will be created in
307 the current directory, and it can be manipulated using the other Ksplice
308 utilities, such as B<ksplice-apply>.
310 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
311 directory, it must build that kernel from scratch, which is much slower than
312 the rest of the update-creation process. B<--prebuild> can be used to perform
313 this initial kernel build without providing a source code patch.
315 In order to patch a function that has previously been patched by Ksplice, the
316 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
317 contains the source for the currently running kernel, including any patches
318 that have previously been applied by Ksplice.
324 =item B<-v>, B<--verbose>
326 Causes B<ksplice-create> to print debugging messages about its progress. Using
327 multiple -v options increases the verbosity. The maximum is 2.
329 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
331 Specifies the number of jobs to run simultaneously while performing kernel
332 builds. B<ksplice-create> also honors the environment variable
335 =item B<--patch-opt=>I<OPTIONS>
337 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
338 B<-p1> is passed to B<patch>. If this option is specified, then only the
339 specified options will be passed to B<patch>. This option can be repeated in
340 order to pass multiple options to B<patch>. This option is ignored when the
341 to-be-applied source code patch is specified using B<--diffext>.
345 Specifies the unique value that will be used as the identifier of the
346 Ksplice update. This identifier will, for example, appear in the name
347 of the update tarball. By default, a random 8-character ID will be
354 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
358 Please report bugs to <PACKAGE_BUGREPORT>.
362 Copyright (C) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
364 Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
365 Tim Abbott <tabbott@mit.edu>
367 This is free software and documentation. You can redistribute and/or modify it
368 under the terms of the GNU General Public License, version 2.