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