Fix orig_label = label invariant in init_label_map.
[ksplice.git] / ksplice-create.in
blob439bf7fb49fdd4497b7f1cbc8c0cfbb587873118
1 #!/usr/bin/perl
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
18 # 02110-1301, USA.
20 use strict;
21 use warnings;
22 use lib 'KSPLICE_DATA_DIR';
23 use Ksplice;
25 my ($patchfile, $diffext, $orig_config_dir, $jobs, $kid);
26 my @only_targets;
27 my @extra_match;
28 my $standalone;
29 my ($prebuild, $skip_prebuild) = (0, 0);
30 my @patch_opt = "-p1";
31 GetOptions(@common_options,
32 "id=s" => \$kid,
33 "patch=s" => \$patchfile,
34 "diffext=s" => \$diffext,
35 "prebuild" => \$prebuild,
36 "only-targets=s" => \@only_targets,
37 "extra-match=s" => \@extra_match,
38 "standalone!" => \$standalone,
39 "skip-prebuild" => \$skip_prebuild,
40 "jobs|j:i" => \$jobs,
41 "config=s" => \$orig_config_dir,
42 "patch-opt=s" => \@patch_opt) or pod2usage(1);
44 pod2usage(1) if($help || scalar(@ARGV) != 1);
45 my $actions = (defined $patchfile) + (defined $diffext) + ($prebuild);
46 pod2usage(1) if($actions != 1);
48 my ($linuxtree) = (abs_path($ARGV[0]));
50 if(!defined $orig_config_dir) {
51 $orig_config_dir = "$linuxtree/ksplice";
53 else {
54 $orig_config_dir = abs_path($orig_config_dir);
55 if($orig_config_dir =~ $linuxtree) {
56 die "Aborting: User-specified ORIG_CONFIG cannot be KERNEL_SOURCE or a subdirectory";
59 if(!defined $orig_config_dir || ! -d $orig_config_dir) {
60 die "Failed to find ORIG_CONFIG directory ($orig_config_dir)";
62 if(! -e "$orig_config_dir/.config") {
63 die "Failed to find .config file in ORIG_CONFIG directory";
65 if(! -e "$orig_config_dir/System.map") {
66 die "Failed to find System.map file in ORIG_CONFIG directory";
69 my $kernel_headers_dir = "$orig_config_dir/build";
70 $kernel_headers_dir = $linuxtree unless(-d $kernel_headers_dir);
72 my @kbuild_flags = ();
73 if(-e "$orig_config_dir/flags") {
74 open(FLAGS, '<', "$orig_config_dir/flags") or die;
75 local $/;
76 @kbuild_flags = shellwords(scalar <FLAGS>);
77 close(FLAGS);
80 $ENV{KSPLICE_VERBOSE} = $Verbose::level;
81 $ENV{KSPLICE_CONFIG_DIR} = $orig_config_dir;
83 my @chars = ('a'..'z', 0..9);
84 $kid = join '', map { $chars[int(rand(36))] } 0..7 if(!defined $kid);
85 my $ksplice = "ksplice-$kid";
86 $ENV{KSPLICE_KID} = $kid;
88 # Some versions of Fedora have System.map files whose symbol addresses disagree
89 # with the running kernel by a constant address offset. Here, Ksplice notes the
90 # System.map address for printk so that it can later compare this address against
91 # the kernel's address for printk. This comparison helps Ksplice work around
92 # this Fedora problem, and this comparison also helps Ksplice detect whether
93 # the user has provided an incorrect System.map file.
94 my $map_printk = runstr("$datadir/ksplice-obj.pl", "system_map_lookup", "printk");
96 print "Starting kernel builds (this process might take a long time)...\n"
97 if($Verbose::level >= 0);
99 $patchfile = abs_path($patchfile) if(defined $patchfile);
101 my $origdir = getcwd();
102 chdir($linuxtree);
104 my @make = ("make", "-rR");
105 if(defined $jobs) {
106 push @make, "-j$jobs";
107 } elsif(defined $ENV{CONCURRENCY_LEVEL}) {
108 push @make, "-j$ENV{CONCURRENCY_LEVEL}";
111 if($Verbose::level >= 2) {
112 push @make, "V=1";
113 } elsif($Verbose::level < 0) {
114 push @make, "-s";
117 my @make_ksplice = (@make, "-f", "$datadir/Makefile.ksplice", @kbuild_flags);
119 sub revert_orig() {
120 for(split(/\0/, runstr(qw(find -name *.KSPLICE* -print0)))) {
121 if(my ($file) = m/^(.*)\.KSPLICE_pre$/) {
122 rename($_, $file);
123 runval("$datadir/ksplice-obj.pl", "snap", "$file.KSPLICE") if(-e "$file.KSPLICE");
124 } elsif(m/\.KSPLICE_(?:primary|helper)$/) {
125 unlink($_) if(-e $_);
129 revert_orig();
131 if(!$skip_prebuild) {
132 copy("$orig_config_dir/.config", "$linuxtree/.config");
133 utime((stat("$orig_config_dir/.config"))[8, 9], "$linuxtree/.config");
134 my @snap_flags = ("KSPLICE_MODE=snap");
135 if(-e "include/config/kernel.release") {
136 push(@snap_flags, "-o", "include/config/kernel.release");
138 runval_raw(@make_ksplice, @snap_flags) == 0 or
139 die "Aborting: Prebuild failed";
140 sleep(1);
142 exit(0) if($prebuild);
144 my $tmpdir = tempdir('ksplice-tmp-XXXXXX', TMPDIR => 1, CLEANUP => 1);
145 copy($patchfile, "$tmpdir/patch") if(defined $patchfile);
146 $patchfile = "$tmpdir/patch";
148 if(defined $diffext) {
149 open(PATCH, '>', $patchfile) or die;
150 for(split(/\0/, runstr("find", "-name", "*$diffext", "-print0"))) {
151 my ($file) = /^(.*)\Q$diffext\E/ or die;
152 print PATCH runstr("diff", "-u", "--", $file, $_);
154 close(PATCH) or die;
155 @patch_opt = ("-p0");
158 my $kmodsrc = "$tmpdir/kmodsrc";
159 runval("cp", "-a", "--", "$datadir/kmodsrc", $kmodsrc);
160 $ENV{KSPLICE_KMODSRC} = $kmodsrc;
162 my @make_kmodsrc = (@make, "-C", $kernel_headers_dir, "M=$kmodsrc", "KSPLICE_KID=$kid", "KSPLICE_VERSION=PACKAGE_VERSION", "map_printk=$map_printk");
164 if (!defined($standalone)) {
165 $standalone = (runval_raw(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
167 push(@make_kmodsrc, "KSPLICE_STANDALONE=1") if ($standalone);
169 runval(@make_kmodsrc);
171 @patch_opt = ("-s", @patch_opt) if ($Verbose::level < 0);
173 runval_infile($patchfile, "patch", @patch_opt, "-bz", ".KSPLICE_pre");
174 push @make_ksplice, "KSPLICE_EXTRA_MATCH=@extra_match" if (@extra_match);
175 push @make_ksplice, "KSPLICE_ONLY_TARGETS=@only_targets" if (@only_targets);
176 if(runval_raw(@make_ksplice, "KSPLICE_MODE=diff") != 0) {
177 revert_orig();
178 die "Aborting: Applying the patch appears to break the kernel build";
181 sub copy_debug {
182 my ($file) = @_;
183 my ($dir, $base) = (dirname($file), basename($file));
184 -d "$tmpdir/objects/$dir" or mkpath("$tmpdir/objects/$dir");
185 copy($file, "$tmpdir/objects/$file");
186 my $cmdfile = "$dir/.$base.cmd";
187 copy($cmdfile, "$tmpdir/objects/$cmdfile") if(-e $cmdfile);
190 mkdir("$tmpdir/objects");
191 for (split(/\0/, runstr(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name .*.KSPLICE.cmd -print0)))) {
192 copy_debug($_);
193 copy_debug($1) if (m/^(.*)\.KSPLICE_pre$/);
196 my @modules = ();
197 foreach(glob(".tmp_versions/*.mod.KSPLICE")) {
198 open MOD, '<', $_;
199 chomp(my $mod = <MOD>);
200 close MOD;
201 foreach my $collect ("$mod.o.KSPLICE", "$mod.o.KSPLICE_primary",
202 "$mod.o.KSPLICE_helper") {
203 copy($collect, "$kmodsrc/" . basename($collect));
205 push @modules, basename($mod);
208 if(!@modules) {
209 revert_orig();
210 die "Aborting: No changes detected";
213 revert_orig();
215 runval(@make_kmodsrc, "modules", "KSPLICE_MODULES=@modules");
217 chdir($tmpdir);
218 mkdir($ksplice);
219 move($patchfile, $ksplice);
220 foreach my $mod (@modules) {
221 (my $target = $mod) =~ s/-/_/g;
222 my $mid = "${kid}_$target";
223 my $module = "ksplice-$mid";
224 rename("$kmodsrc/$module.ko", "$ksplice/$module.ko");
225 rename("$kmodsrc/$module-helper.ko", "$ksplice/$module-helper.ko");
227 rename("$kmodsrc/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko") if ($standalone);
229 mkdir("$ksplice/debug");
230 rename("objects", "$ksplice/debug/objects");
231 rename("$kmodsrc", "$ksplice/debug/kmodsrc");
232 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
233 copy("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
235 print "Ksplice update tarball written to $ksplice.tar.gz\n";
236 exit(0);
238 =head1 NAME
240 ksplice-create - Create a set of kernel modules for a rebootless kernel update
242 =head1 SYNOPSIS
244 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
246 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
248 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
250 =head1 DESCRIPTION
252 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
253 will apply a user-specified source code patch to the running binary kernel.
255 Before you use B<ksplice-create> on a patch, you should confirm that the
256 desired source code change does not make any semantic changes to kernel data
257 structures--that is, changes that would require existing instances of kernel
258 data structures to be transformed (e.g., a patch that adds a field to a global
259 data structure would require the existing data structures to change). If you
260 use Ksplice on a patch that changes data structure semantics, Ksplice will not
261 detect the problem and you could experience kernel problems as a result.
263 The to-be-applied source code patch can be specified by providing a L<patch(1)>
264 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
265 (B<--diffext=>I<EXTENSION>).
267 If a file extension is specified, then the desired source code patch will be
268 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
269 whose names end with the extra extension I<EXTENSION> against the corresponding
270 files without the extra extension. Only the new files containing the extra
271 extension in their filenames should be modified.
273 Here is an example of using a file extension to specify a patch:
275 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
276 [edit sys.c.prctl_fixed to include the desired changes]
277 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
279 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
280 original source code. If your Linux distribution applies patches to the Linux
281 kernel during the kernel build process, then those patches must be applied to
282 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
283 directory. B<ksplice-create> will not modify the source code in the
284 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
285 directory tree.
287 I<ORIG_CONFIG> can be used to specify the directory containing the
288 to-be-updated kernel's original F<.config> file and original F<System.map> file
289 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
290 I<KERNEL_SOURCE>B</ksplice>.
292 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
293 close to the compiler and assembler originally used to build the running kernel
294 as possible. If the current compiler and linker are too different from the
295 original compiler and linker, B<ksplice-apply> will abort when applying the
296 update.
298 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
299 containing the desired Ksplice update modules. This tarball will be created in
300 the current directory, and it can be manipulated using the other Ksplice
301 utilities, such as B<ksplice-apply>.
303 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
304 directory, it must build that kernel from scratch, which is much slower than
305 the rest of the update-creation process. B<--prebuild> can be used to perform
306 this initial kernel build without providing a source code patch.
308 In order to patch a function that has previously been patched by Ksplice, the
309 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
310 contains the source for the currently running kernel, including any patches
311 that have previously been applied by Ksplice.
313 =head1 OPTIONS
315 =over 8
317 =item B<-v>, B<--verbose>
319 Causes B<ksplice-create> to print debugging messages about its progress. Using
320 multiple -v options increases the verbosity. The maximum is 2.
322 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
324 Specifies the number of jobs to run simultaneously while performing kernel
325 builds. B<ksplice-create> also honors the environment variable
326 CONCURRENCY_LEVEL.
328 =item B<--patch-opt=>I<OPTIONS>
330 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
331 B<-p1> is passed to B<patch>. If this option is specified, then only the
332 specified options will be passed to B<patch>. This option can be repeated in
333 order to pass multiple options to B<patch>. This option is ignored when the
334 to-be-applied source code patch is specified using B<--diffext>.
336 =item B<--id=>I<ID>
338 Specifies the unique value that will be used as the identifier of the
339 Ksplice update. This identifier will, for example, appear in the name
340 of the update tarball. By default, a random 8-character ID will be
341 generated.
343 =back
345 =head1 BUGS
347 Please report bugs to <PACKAGE_BUGREPORT>.
349 =head1 SEE ALSO
351 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
353 =head1 COPYRIGHT
355 Copyright (C) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
356 Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
357 Tim Abbott <tabbott@mit.edu>
359 This is free software and documentation. You can redistribute and/or modify it
360 under the terms of the GNU General Public License, version 2.
362 =cut