Do not write Ksplice relocations to the middle of a patched section.
[ksplice.git] / ksplice-create.in
blob8462015a0db38d3edd9c394dd1ba4b2a083ebb7a
1 #!/usr/bin/perl
3 # Copyright (C) 2007-2009 Ksplice, Inc.
4 # Authors: Jeff Arnold, Anders Kaseorg, Tim Abbott
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License, version 2.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
17 # 02110-1301, USA.
19 use strict;
20 use warnings;
21 use lib 'KSPLICE_DATA_DIR';
22 use Ksplice;
24 my ($patchfile, $diffext, $git, $orig_config_dir, $jobs, $kid);
25 my $description;
26 my $series = 0;
27 my $build_modules = 0;
28 my @only_targets;
29 my @extra_match;
30 my $standalone;
31 my ($prebuild, $skip_prebuild) = (0, 0);
32 my @patch_opt = "-p1";
33 GetOptions(@common_options,
34 "id=s" => \$kid,
35 "patch=s" => \$patchfile,
36 "description=s" => \$description,
37 "diffext=s" => \$diffext,
38 "git=s" => \$git,
39 "prebuild" => \$prebuild,
40 "series!" => \$series,
41 "build-modules!" => \$build_modules,
42 "only-targets=s" => \@only_targets,
43 "extra-match=s" => \@extra_match,
44 "standalone!" => \$standalone,
45 "skip-prebuild" => \$skip_prebuild,
46 "jobs|j:i" => \$jobs,
47 "config=s" => \$orig_config_dir,
48 "patch-opt=s" => \@patch_opt) or pod2usage(1);
50 pod2usage(1) if($help || scalar(@ARGV) != 1);
51 my $actions = (defined $patchfile) + (defined $diffext) + (defined $git) + $prebuild;
52 pod2usage(1) if($actions != 1);
54 my $have_Git = eval { require Git };
55 $have_Git or die $@ if defined $git;
57 my ($linuxtree) = (abs_path($ARGV[0]));
59 if(!defined $orig_config_dir) {
60 $orig_config_dir = "$linuxtree/ksplice";
62 else {
63 $orig_config_dir = abs_path($orig_config_dir);
64 if($orig_config_dir =~ $linuxtree) {
65 die "Aborting: User-specified ORIG_CONFIG cannot be KERNEL_SOURCE or a subdirectory";
68 if(!defined $orig_config_dir || ! -d $orig_config_dir) {
69 die "Failed to find ORIG_CONFIG directory ($orig_config_dir)";
71 if(! -e "$orig_config_dir/System.map") {
72 die "Failed to find System.map file in ORIG_CONFIG directory";
75 my $kernel_headers_dir = "$orig_config_dir/build";
76 $kernel_headers_dir = $linuxtree unless(-d $kernel_headers_dir);
78 my @kbuild_flags = ();
79 if(-e "$orig_config_dir/flags") {
80 open(FLAGS, '<', "$orig_config_dir/flags") or die;
81 local $/;
82 @kbuild_flags = shellwords(scalar <FLAGS>);
83 close(FLAGS);
86 $ENV{KSPLICE_VERBOSE} = $Verbose::level;
87 $ENV{KSPLICE_CONFIG_DIR} = $orig_config_dir;
89 my @chars = ('a'..'z', 0..9);
90 $kid = join '', map { $chars[int(rand(36))] } 0..7 if(!defined $kid);
91 my $ksplice = "ksplice-$kid";
92 $ENV{KSPLICE_KID} = $kid;
94 # Some versions of Fedora have System.map files whose symbol addresses disagree
95 # with the running kernel by a constant address offset. Here, Ksplice notes the
96 # System.map address for printk so that it can later compare this address against
97 # the kernel's address for printk. This comparison helps Ksplice work around
98 # this Fedora problem, and this comparison also helps Ksplice detect whether
99 # the user has provided an incorrect System.map file.
100 my $map_printk = runstr("$datadir/ksplice-obj.pl", "system_map_lookup", "printk");
102 print "Starting kernel builds (this process might take a long time)...\n"
103 if($Verbose::level >= 0);
105 $patchfile = abs_path($patchfile) if(defined $patchfile);
107 my $origdir = getcwd();
108 chdir($linuxtree);
110 my $git_rev;
111 my $git_repo;
112 if (defined $git) {
113 $git_repo = Git->repository();
114 ($git_rev) = $git_repo->command(qw(rev-parse --verify), $git);
115 } else {
116 $git_repo = eval { Git->repository() };
119 my @make = ("make", "-rR");
120 if(defined $jobs) {
121 push @make, "-j$jobs";
122 } elsif(defined $ENV{CONCURRENCY_LEVEL}) {
123 push @make, "-j$ENV{CONCURRENCY_LEVEL}";
126 if($Verbose::level >= 2) {
127 push @make, "V=1";
128 } elsif($Verbose::level < 0) {
129 push @make, "-s";
132 $ENV{PATH} = "$datadir:$ENV{PATH}";
133 my @make_ksplice = (@make, "-f", "$datadir/Makefile.ksplice", @kbuild_flags);
135 push(@make_ksplice, "KSPLICE_BUILD_MODULES=1") if ($build_modules);
136 if(-e "include/config/kernel.release") {
137 push(@make_ksplice, "-o", "include/config/kernel.release");
140 my @revert_flags = ("KSPLICE_MODE=revert");
141 push(@revert_flags, "KSPLICE_SERIES=y") if ($series);
143 sub git_have_ksplice_pre {
144 return $git_repo->command(qw(for-each-ref refs/ksplice/pre)) ne '';
147 if(-e "$orig_config_dir/.config" && !-e "$linuxtree/.config") {
148 copy("$orig_config_dir/.config", "$linuxtree/.config");
149 utime((stat("$orig_config_dir/.config"))[8, 9],
150 "$linuxtree/.config");
153 sub revert_orig() {
154 for(split(/\0/, runstr(qw(find -name *.KSPLICE_presrc -print0)))) {
155 my ($file) = m/^(.*)\.KSPLICE_presrc$/;
156 if ($series) {
157 unlink($_);
158 } else {
159 rename($_, $file);
162 if (defined $git_repo && git_have_ksplice_pre) {
163 if ($series) {
164 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: freeze", qw(refs/ksplice/pre HEAD refs/ksplice/pre));
165 } else {
166 $git_repo->command_noisy(qw(update-index --refresh));
167 $git_repo->command_noisy(qw(read-tree -m --trivial -u refs/ksplice/pre));
168 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: revert", qw(HEAD refs/ksplice/pre HEAD));
171 runval(@make_ksplice, @revert_flags);
173 revert_orig();
175 if (defined $git_repo && !git_have_ksplice_pre) {
176 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: snap", qw(refs/ksplice/pre HEAD), '');
179 if(!$skip_prebuild) {
180 if(-e "$orig_config_dir/.config") {
181 copy("$orig_config_dir/.config", "$linuxtree/.config");
182 utime((stat("$orig_config_dir/.config"))[8, 9],
183 "$linuxtree/.config");
185 my @snap_flags = ("KSPLICE_MODE=snap");
186 runval_raw(@make_ksplice, @snap_flags) == 0 or
187 die "Aborting: Prebuild failed";
188 sleep(1);
190 exit(0) if($prebuild);
192 my $tmpdir = tempdir('ksplice-tmp-XXXXXX', TMPDIR => 1, CLEANUP => 1);
193 copy($patchfile, "$tmpdir/patch") if(defined $patchfile);
194 $patchfile = "$tmpdir/patch";
196 if(defined $diffext) {
197 open(PATCH, '>', $patchfile) or die;
198 for(split(/\0/, runstr("find", "-name", "*$diffext", "-print0"))) {
199 my ($file) = /^(.*)\Q$diffext\E/ or die;
200 print PATCH runstr("diff", "-u", "--", $file, $_);
202 close(PATCH) or die;
203 @patch_opt = ("-p0");
206 my $kmodsrc = "$tmpdir/kmodsrc";
207 runval("cp", "-a", "--", "$datadir/kmodsrc", $kmodsrc);
208 $ENV{KSPLICE_KMODSRC} = $kmodsrc;
210 my @make_kmodsrc = (@make, "-C", $kernel_headers_dir, "M=$kmodsrc", "KSPLICE_KID=$kid", "KSPLICE_VERSION=PACKAGE_VERSION", "map_printk=$map_printk");
212 if (!defined($standalone)) {
213 $standalone = (!-e "$linuxtree/.config" || runval_raw(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
215 push(@make_kmodsrc, "KSPLICE_STANDALONE=1") if ($standalone);
217 runval(@make_kmodsrc);
219 @patch_opt = ("-s", @patch_opt) if ($Verbose::level < 0);
221 if (defined $git) {
222 $git_repo->command_noisy(qw(update-index --refresh));
223 $git_repo->command_noisy(qw(read-tree -m --trivial -u), $git_rev);
224 $git_repo->command_noisy(qw(update-ref -m), "ksplice-create: diff", "HEAD", $git_rev);
226 open(PATCH, '>', $patchfile) or die;
227 if ($git_repo->command(qw(rev-parse --verify HEAD^)) eq
228 $git_repo->command(qw(rev-parse --verify refs/ksplice/pre))) {
229 print PATCH scalar($git_repo->command(qw(log -1 HEAD --))), "\n";
231 print PATCH scalar($git_repo->command(qw(diff-tree -p refs/ksplice/pre HEAD --)));
232 close(PATCH) or die;
233 } else {
234 runval_infile($patchfile, "patch", @patch_opt, "-bz", ".KSPLICE_presrc");
237 my @diff_flags = ("KSPLICE_MODE=diff");
238 push @diff_flags, "KSPLICE_EXTRA_MATCH=@extra_match" if (@extra_match);
239 push @diff_flags, "KSPLICE_ONLY_TARGETS=@only_targets" if (@only_targets);
240 if(runval_raw(@make_ksplice, @diff_flags) != 0) {
241 revert_orig() if(defined($diffext));
242 die "Aborting: Applying the patch appears to break the kernel build";
245 sub copy_debug {
246 my ($file) = @_;
247 my ($dir, $base) = (dirname($file), basename($file));
248 -d "$tmpdir/objects/$dir" or mkpath("$tmpdir/objects/$dir");
249 copy($file, "$tmpdir/objects/$file");
250 my $cmdfile = "$dir/.$base.cmd";
251 copy($cmdfile, "$tmpdir/objects/$cmdfile") if(-e $cmdfile);
254 mkdir("$tmpdir/objects");
255 for (split(/\0/, runstr(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name .*.KSPLICE.cmd -print0)))) {
256 next if (basename($_) =~ m/^(?:vmlinux|vmlinux\.o|\.tmp_vmlinux[0-9]+|\.tmp_kallsyms[0-9]+.o)\.KSPLICE_pre$/);
257 copy_debug($_);
258 copy_debug($1) if (m/^(.*)\.KSPLICE_pre(?:src)?$/);
261 my @modulepaths = ();
262 my @modules = ();
263 foreach(glob("$kmodsrc/*.mod.KSPLICE")) {
264 open MOD, '<', $_;
265 chomp(my $mod = <MOD>);
266 close MOD;
267 push @modulepaths, "$mod.ko" if (basename($mod) ne "vmlinux");
268 push @modules, basename($mod);
271 if(!@modules) {
272 revert_orig() if(defined($diffext));
273 print STDERR "No changes detected.\n";
274 exit(66);
277 if ($build_modules) {
278 mkdir("$tmpdir/modules");
279 runval(@make_ksplice, "KSPLICE_MODE=modinst", "MODLIB=$tmpdir/modules", "INSTALL_MOD_STRIP=1", "modules=@modulepaths");
282 revert_orig() if(defined($diffext));
284 runval(@make_kmodsrc, "modules", "KSPLICE_MODULES=@modules");
285 runval(@make_kmodsrc, qw(modules_install --old-file=_modinst_post --old-file=_emodinst_post), "MAKE=make --old-file=_modinst_post --old-file=_emodinst_post", "INSTALL_MOD_STRIP=1", "MODLIB=$tmpdir/ksplice-modules", "KSPLICE_MODULES=@modules");
287 chdir($tmpdir);
288 mkdir($ksplice);
289 move($patchfile, $ksplice);
290 if ($description) {
291 write_file("$ksplice/description", "$description\n");
293 write_file("$ksplice/api-version", "KSPLICE_API_VERSION\n");
294 write_file("$ksplice/timestamp", time() . "\n");
295 runval_outfile("$ksplice/utsname", "/usr/local/libexec/ksplice-kernel-utsname", "$kmodsrc/offsets.o");
296 open(CONTENTS, ">", "$ksplice/contents");
297 foreach my $mod (@modules) {
298 (my $target = $mod) =~ s/-/_/g;
299 my $mid = "${kid}_$target";
300 my $module = "ksplice-$mid";
301 rename("$tmpdir/ksplice-modules/extra/$module.ko", "$ksplice/$module.ko");
302 print CONTENTS "primary $target ksplice_$mid $module.ko\n";
303 rename("$tmpdir/ksplice-modules/extra/$module-helper.ko", "$ksplice/$module-helper.ko");
304 print CONTENTS "helper $target ksplice_$mid $module-helper.ko\n";
306 if ($standalone) {
307 rename("$tmpdir/ksplice-modules/extra/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko");
308 print CONTENTS "core ksplice_$kid ksplice-$kid.ko\n";
310 if ($build_modules) {
311 foreach my $mod (@modulepaths) {
312 (my $target = basename($mod)) =~ s/-/_/g;
313 print CONTENTS "target $target $mod\n";
317 mkdir("$ksplice/debug");
318 rename("objects", "$ksplice/debug/objects");
319 rename("modules", "$ksplice/modules") if ($build_modules);
320 rename("$kmodsrc", "$ksplice/debug/kmodsrc");
322 close(CONTENTS);
323 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
324 copy("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
325 print "Ksplice update tarball written to $ksplice.tar.gz\n";
326 exit(0);
328 =head1 NAME
330 ksplice-create - Create a set of kernel modules for a rebootless kernel update
332 =head1 SYNOPSIS
334 B<ksplice-create> [I<OPTIONS>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
336 B<ksplice-create> [I<OPTIONS>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
338 B<ksplice-create> [I<OPTIONS>] B<--git=>I<COMMIT> I<KERNEL_SOURCE>
340 B<ksplice-create> [I<OPTIONS>] B<--prebuild> I<KERNEL_SOURCE>
342 =head1 DESCRIPTION
344 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
345 will apply a user-specified source code patch to the running binary kernel.
347 Before you use B<ksplice-create> on a patch, you should confirm that the
348 desired source code change does not make any semantic changes to kernel data
349 structures--that is, changes that would require existing instances of kernel
350 data structures to be transformed (e.g., a patch that adds a field to a global
351 data structure would require the existing data structures to change). If you
352 use Ksplice on a patch that changes data structure semantics, Ksplice will not
353 detect the problem and you could experience kernel problems as a result.
355 The to-be-applied source code patch can be specified by providing a L<patch(1)>
356 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
357 (B<--diffext=>I<EXTENSION>).
359 If a file extension is specified, then the desired source code patch will be
360 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
361 whose names end with the extra extension I<EXTENSION> against the corresponding
362 files without the extra extension. Only the new files containing the extra
363 extension in their filenames should be modified.
365 Here is an example of using a file extension to specify a patch:
367 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
368 [edit sys.c.prctl_fixed to include the desired changes]
369 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
371 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
372 original source code. If your Linux distribution applies patches to the Linux
373 kernel during the kernel build process, then those patches must be applied to
374 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
375 directory. B<ksplice-create> will not modify the source code in the
376 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
377 directory tree.
379 I<ORIG_CONFIG> can be used to specify the directory containing the
380 to-be-updated kernel's original F<.config> file and original F<System.map> file
381 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
382 I<KERNEL_SOURCE>B</ksplice>.
384 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
385 close to the compiler and assembler originally used to build the running kernel
386 as possible. If the current compiler and linker are too different from the
387 original compiler and linker, B<ksplice-apply> will abort when applying the
388 update.
390 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
391 containing the desired Ksplice update modules. This tarball will be created in
392 the current directory, and it can be manipulated using the other Ksplice
393 utilities, such as B<ksplice-apply>.
395 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
396 directory, it must build that kernel from scratch, which is much slower than
397 the rest of the update-creation process. B<--prebuild> can be used to perform
398 this initial kernel build without providing a source code patch.
400 In order to patch a function that has previously been patched by Ksplice, the
401 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
402 contains the source for the currently running kernel, including any patches
403 that have previously been applied by Ksplice.
405 =head1 OPTIONS
407 =over 8
409 =item B<--patch=>I<PATCH_FILE>
411 Builds a Ksplice update out of the given L<patch(1)> file I<PATCH_FILE>.
413 =item B<--diffext=>I<EXTENSION>
415 Builds a Ksplice update using the modified source files with names ending in
416 I<EXTENSION>. The patch will be determined by comparing all of the files in the
417 I<KERNEL_SOURCE> directory tree whose names end with the extra extension
418 I<EXTENSION> against the corresponding files without the extra extension.
420 =item B<--git>=I<COMMIT>
422 Builds a Ksplice update using the commit I<COMMIT> in the Git working tree
423 I<KERNEL_SOURCE>. The original state corresponding to the running kernel is
424 remembered in the Git ref B<refs/ksplice/pre>, which will be created from the
425 current B<HEAD> if it does not yet exist (and can be changed using the
426 B<--series> option). Therefore, the source code change to be applied
427 corresponds to the output of B<git diff ksplice/pre> I<COMMIT>.
429 =item B<--prebuild>
431 Compiles the original source code that will be needed to build future Ksplice
432 updates. If any Ksplice updates have previously been built in the
433 I<KERNEL_SOURCE> tree, the source files in the tree are reverted to their
434 original state.
436 =item B<--series>
438 Specifies that the current state of the I<KERNEL_SOURCE> tree should be used as
439 the original source that corresponds to the running kernel. If a Ksplice update
440 has recently been built in the I<KERNEL_SOURCE> tree, this option specifies that
441 the Ksplice update being built should be applied after the previous update in
442 series. This option can be used with B<--prebuild> to forget the previous
443 original state and perform no other action.
445 =item B<--build-modules>
447 For a patch that includes changes to kernel modules, in addition to building a
448 hot update that can be applied to the running kernel, this option will cause
449 B<ksplice-create> to generate a set of new modules based on the updated source
450 code. These modules can be used to replace the kernel modules stored on disk,
451 where they can later be loaded normally after part of the hot update has been
452 applied using L<ksplice-apply(1)> B<--partial>.
454 =item B<-v>, B<--verbose>
456 Causes B<ksplice-create> to print debugging messages about its progress. Using
457 multiple -v options increases the verbosity. The maximum is 2.
459 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
461 Specifies the number of jobs to run simultaneously while performing kernel
462 builds. B<ksplice-create> also honors the environment variable
463 CONCURRENCY_LEVEL.
465 =item B<--patch-opt=>I<OPTIONS>
467 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
468 B<-p1> is passed to B<patch>. If this option is specified, then only the
469 specified options will be passed to B<patch>. This option can be repeated in
470 order to pass multiple options to B<patch>. This option is ignored when the
471 to-be-applied source code patch is specified using B<--diffext>.
473 =item B<--id=>I<ID>
475 Specifies the unique value that will be used as the identifier of the
476 Ksplice update. This identifier will, for example, appear in the name
477 of the update tarball. By default, a random 8-character ID will be
478 generated.
480 =back
482 =head1 SEE ALSO
484 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
486 =head1 BUGS
488 Please report bugs to <PACKAGE_BUGREPORT>.
490 =head1 AUTHORS
492 Jeff Arnold, Anders Kaseorg, and Tim Abbott
494 =head1 COPYRIGHT
496 Copyright (C) 2007-2009 Ksplice, Inc.
498 This is free software and documentation. You can redistribute and/or modify it
499 under the terms of the GNU General Public License, version 2.
501 =cut