Use Fatal and verbose in ksplice.pl.
[ksplice.git] / ksplice-create.in
blobc1a44834dc01a27aecd4f04c488ee18cc3eee5ca
1 #!/usr/bin/perl
3 # Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License, version 2.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
16 # 02110-1301, USA.
18 use Getopt::Long;
19 use Cwd 'abs_path', 'getcwd';
20 use File::Basename;
21 use File::Copy;
22 use File::Path;
23 use File::Temp;
24 use Fatal qw(:void copy rename move chdir mkdir unlink rmtree);
25 use Pod::Usage;
26 use strict;
27 use warnings;
28 use lib 'KSPLICE_DATA_DIR';
29 use ksplice;
30 use verbose qw(copy rename move chdir mkdir mkpath unlink rmtree mktemp mkdtemp);
32 my ($patchfile, $diffext, $orig_config_dir, $jobs, $kid);
33 my $standalone;
34 my ($help, $wantversion, $prebuild, $skip_prebuild, $apply, $patch_opt) = (0, 0, 0, 0, 0, "-p1");
35 Getopt::Long::Configure("bundling");
36 GetOptions("help|?" => \$help,
37 "version" => \$wantversion,
38 "verbose|v!" => \$verbose::level,
39 "id=s" => \$kid,
40 "patch=s" => \$patchfile,
41 "diffext=s" => \$diffext,
42 "prebuild" => \$prebuild,
43 "standalone!" => \$standalone,
44 "skip-prebuild" => \$skip_prebuild,
45 "jobs|j:i" => \$jobs,
46 "config=s" => \$orig_config_dir,
47 "apply" => \$apply,
48 "patch-opt=s@" => \$patch_opt) or pod2usage(1);
50 if($wantversion) {
51 print $version_str;
52 exit(0);
54 pod2usage(1) if($help || scalar(@ARGV) != 1);
55 my $actions = (defined $patchfile) + (defined $diffext) + ($prebuild);
56 pod2usage(1) if($actions != 1);
58 my ($linuxtree) = (abs_path($ARGV[0]));
60 my $tmpdir = init_tmpdir();
61 copy($patchfile, "$tmpdir/patch") if(defined $patchfile);
62 $patchfile = "$tmpdir/patch";
64 $patch_opt = "-p0" if(defined $diffext);
65 $patch_opt = join(" ", @$patch_opt) if(ref $patch_opt);
67 if(!defined $orig_config_dir) {
68 $orig_config_dir = "$linuxtree/ksplice";
70 else {
71 $orig_config_dir = abs_path($orig_config_dir);
72 if($orig_config_dir =~ $linuxtree) {
73 die "Aborting: User-specified ORIG_CONFIG cannot be KERNEL_SOURCE or a subdirectory";
76 if(!defined $orig_config_dir || ! -d $orig_config_dir) {
77 die "Failed to find ORIG_CONFIG directory ($orig_config_dir)";
79 if(! -e "$orig_config_dir/.config") {
80 die "Failed to find .config file in ORIG_CONFIG directory";
82 if(! -e "$orig_config_dir/System.map") {
83 die "Failed to find System.map file in ORIG_CONFIG directory";
86 $ENV{KSPLICE_VERBOSE} = $verbose::level;
87 $ENV{KSPLICE_CONFIG_DIR} = $orig_config_dir;
89 my @standalone_flag;
90 my $ksplice_in_kernel = runstr(qw(grep ^CONFIG_KSPLICE=), "$orig_config_dir/.config");
91 $ksplice_in_kernel =~ s/^CONFIG_KSPLICE=([nmy])/$1/;
92 chomp($ksplice_in_kernel);
93 if (!defined($standalone)) {
94 $standalone = 0;
95 $standalone = 1 if ($ksplice_in_kernel ne 'y' && $ksplice_in_kernel ne 'm');
97 @standalone_flag = qw(KSPLICE_STANDALONE=1) if ($standalone == 1);
99 copy("$orig_config_dir/.config", "$linuxtree/.config");
101 my @chars = ('a'..'z', 0..9);
102 $kid = join '', map { $chars[int(rand(36))] } 0..7 if(!defined $kid);
103 my $ksplice = "ksplice-$kid";
105 # Some versions of Fedora have System.map files whose symbol addresses disagree
106 # with the running kernel by a constant address offset. Here, Ksplice notes the
107 # System.map address for printk so that it can later compare this address against
108 # the kernel's address for printk. This comparison helps Ksplice work around
109 # this Fedora problem, and this comparison also helps Ksplice detect whether
110 # the user has provided an incorrect System.map file.
111 my $map_printk = runstr("$datadir/ksplice.pl", "system_map_lookup", "printk");
113 print "Starting kernel builds (this process might take a long time)...\n";
114 if(!$verbose::level) {
115 print "For output during this process, run ksplice-create with the option -v\n";
118 ###################################################################
119 # PHASE 1: Determine which object files are modified by the patch #
120 # - performs the pre and post kernel builds #
121 # - uses objdiff to identify which ELF sections have changed and #
122 # which ELF symbols are entry points to those sections #
123 ###################################################################
125 # We will refer to the object files modified by the patch as the "target object
126 # files", the ELF sections changed by the patch as the "target sections", and
127 # the entry points of those sections as the "target entry points".
129 my $origdir = getcwd();
130 chdir($linuxtree);
131 if(defined $diffext) {
132 runval("$libexecdir/ksplice-gendiff-reversed >$patchfile . $diffext");
135 my @jlevel = (defined $ENV{CONCURRENCY_LEVEL} ? ("-j$ENV{CONCURRENCY_LEVEL}") : ());
136 @jlevel = ("-j$jobs") if(defined $jobs);
137 my @make_ksplice = ("make", "-f", "$datadir/Makefile.ksplice", @jlevel);
139 sub revert_orig() {
140 for (split(/\0/, runstr(qw(find -name *.KSPLICE_pre -print0)))) {
141 s/\.KSPLICE_pre$//;
142 rename("$_.KSPLICE_pre", $_);
143 unlink("$_.KSPLICE") if(-e "$_.KSPLICE");
146 revert_orig();
148 if(!$skip_prebuild &&
149 runval_raw(@make_ksplice, "KSPLICE_MODE=snap") != 0) {
150 die "Aborting: Prebuild failed";
152 exit(0) if($prebuild);
153 runval("patch $patch_opt -bz .KSPLICE_pre < $patchfile");
154 if(runval_raw(@make_ksplice, "KSPLICE_MODE=diff") != 0) {
155 revert_orig();
156 die "Aborting: Applying the patch appears to break the kernel build";
159 sub copy_debug {
160 my ($file) = @_;
161 my ($dir, $base) = (dirname($file), basename($file));
162 mkpath("$tmpdir/objects/$dir");
163 copy($file, "$tmpdir/objects/$file");
164 my $cmdfile = "$dir/.$base.cmd";
165 copy($cmdfile, "$tmpdir/objects/$cmdfile") if(-e $cmdfile);
168 mkdir("$tmpdir/objects");
169 for (split(/\0/, runstr(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name .*.KSPLICE.cmd -print0)))) {
170 copy_debug($_);
171 copy_debug($1) if (m/^(.*)\.KSPLICE_pre$/);
174 mkdir("$tmpdir/collect");
176 my @modules = ();
177 foreach(glob(".tmp_versions/*.mod.KSPLICE")) {
178 open MOD, '<', $_;
179 chomp(my $module = <MOD>);
180 close MOD;
181 foreach my $collect ("$module.o.KSPLICE", "$module.o.KSPLICE_primary",
182 "$module.o.KSPLICE_helper") {
183 copy($collect, "$tmpdir/collect/" . basename($collect));
185 push @modules, basename($module);
188 if(!@modules) {
189 revert_orig();
190 die "Aborting: No changes detected";
193 revert_orig();
195 for my $module (@modules) {
196 chdir("$tmpdir/collect");
198 ################################################################################
199 # PHASE 3: Combine the target object files and prepare for kernel module build #
200 # - links the many target object files into two "collection" object files #
201 # - saves the reloc info extracted earlier in ELF sect .ksplice.ksplice_relocs #
202 # - uses objmanip's sizelist mode to save the names and sizes of target funcs #
203 # - uses ld-script to aggregate all ELF text sections into .text #
204 # - saves the list of target entry syms in ELF sect .ksplice.ksplice_patches #
205 ################################################################################
207 chdir($tmpdir);
208 runval("cp", "-a", "--", "$datadir/kmodsrc", "kmodsrc-$module");
209 rename("collect/$module.o.KSPLICE_primary", "kmodsrc-$module/collection.o.primary");
210 rename("collect/$module.o.KSPLICE_helper", "kmodsrc-$module/collection.o.helper");
211 chdir("kmodsrc-$module");
213 rename("collection.o.primary", "collection.o.primary.preld");
214 runval("ld", "--script=ld-script", "-r", "-o", "collection.o.primary", "collection.o.primary.preld");
215 rename("collection.o.helper", "collection.o.helper.preld");
216 runval("ld", "--script=ld-script", "-r", "-o", "collection.o.helper", "collection.o.helper.preld");
218 ###############################################################################
219 # PHASE 4: Build the kernel modules and create the update tarball #
220 # - builds primary and helper kernel modules #
221 # - uses objmanip's rmsyms mode to remove relocations to non-exported symbols #
222 # - creates a tarball of the primary module and the helper module #
223 ###############################################################################
225 my $kid_m = "${kid}_$module";
226 $kid_m =~ s/-/_/g;
227 my $ksplice_m = "ksplice-$kid_m";
228 runval("make", @jlevel, "modules", "KSPLICE_ID=$kid_m", "KSPLICE_TARGET=$module", "map_printk=$map_printk", "KERNELSRC=$linuxtree", @standalone_flag);
231 chdir($tmpdir);
232 mkdir($ksplice);
233 move($patchfile, $ksplice);
234 for my $module (@modules) {
235 my $kid_m = "${kid}_$module";
236 $kid_m =~ s/-/_/g;
237 my $ksplice_m = "ksplice-$kid_m";
238 rename("kmodsrc-$module/$ksplice_m.ko", "$ksplice/$ksplice_m.ko");
239 rename("kmodsrc-$module/$ksplice_m-helper.ko", "$ksplice/$ksplice_m-helper.ko");
241 if($ksplice_in_kernel eq 'm' && ! $standalone) {
242 open FILE, '>', "$ksplice/need_modprobe_ksplice" and close FILE or die;
244 mkdir("$ksplice/debug");
245 rename("objects", "$ksplice/debug/objects");
246 rename("collect", "$ksplice/debug/collect");
247 for my $module (@modules) {
248 rename("kmodsrc-$module", "$ksplice/debug/kmodsrc-$module");
250 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
251 copy("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
252 chdir($origdir);
253 rmtree($tmpdir);
255 print "Ksplice update tarball written to $ksplice.tar.gz\n";
257 if($apply) {
258 print "Now running ksplice-apply to apply update...\n";
259 exec("ksplice-apply", $ksplice) || die;
262 exit(0);
264 =head1 NAME
266 ksplice-create - Create a set of kernel modules for a rebootless kernel update
268 =head1 SYNOPSIS
270 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
272 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
274 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
276 =head1 DESCRIPTION
278 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
279 will apply a user-specified source code patch to the running binary kernel.
281 Before you use B<ksplice-create> on a patch, you should confirm that the
282 desired source code change does not make any semantic changes to kernel data
283 structures--that is, changes that would require existing instances of kernel
284 data structures to be transformed (e.g., a patch that adds a field to a global
285 data structure would require the existing data structures to change). If you
286 use Ksplice on a patch that changes data structure semantics, Ksplice will not
287 detect the problem and you could experience kernel problems as a result.
289 The to-be-applied source code patch can be specified by providing a L<patch(1)>
290 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
291 (B<--diffext=>I<EXTENSION>).
293 If a file extension is specified, then the desired source code patch will be
294 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
295 whose names end with the extra extension I<EXTENSION> against the corresponding
296 files without the extra extension. Only the new files containing the extra
297 extension in their filenames should be modified.
299 Here is an example of using a file extension to specify a patch:
301 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
302 [edit sys.c.prctl_fixed to include the desired changes]
303 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
305 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
306 original source code. If your Linux distribution applies patches to the Linux
307 kernel during the kernel build process, then those patches must be applied to
308 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
309 directory. B<ksplice-create> will not modify the source code in the
310 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
311 directory tree.
313 I<ORIG_CONFIG> can be used to specify the directory containing the
314 to-be-updated kernel's original F<.config> file and original F<System.map> file
315 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
316 I<KERNEL_SOURCE>B</ksplice>.
318 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
319 close to the compiler and assembler originally used to build the running kernel
320 as possible. If the current compiler and linker are too different from the
321 original compiler and linker, B<ksplice-apply> will abort when applying the
322 update.
324 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
325 containing the desired Ksplice update modules. This tarball will be created in
326 the current directory, and it can be manipulated using the other Ksplice
327 utilities, such as B<ksplice-apply>.
329 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
330 directory, it must build that kernel from scratch, which is much slower than
331 the rest of the update-creation process. B<--prebuild> can be used to perform
332 this initial kernel build without providing a source code patch.
334 In order to patch a function that has previously been patched by Ksplice, the
335 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
336 contains the source for the currently running kernel, including any patches
337 that have previously been applied by Ksplice.
339 =head1 OPTIONS
341 =over 8
343 =item B<-v>, B<--verbose>
345 Prints the commands being executed, the output of the commands being executed,
346 and various other pieces of information.
348 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
350 Specifies the number of jobs to run simultaneously while performing kernel
351 builds. B<ksplice-create> also honors the environment variable
352 CONCURRENCY_LEVEL.
354 =item B<--apply>
356 Immediately applies the generated update to the running kernel by invoking
357 B<ksplice-apply>.
359 =item B<--patch-opt=>I<OPTIONS>
361 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
362 B<-p1> is passed to B<patch>. If this option is specified, then only the
363 specified options will be passed to B<patch>. This option can be repeated in
364 order to pass multiple options to B<patch>. This option is ignored when the
365 to-be-applied source code patch is specified using B<--diffext>.
367 =item B<--id=>I<ID>
369 Specifies the unique value that will be used as the identifier of the
370 Ksplice update. This identifier will, for example, appear in the name
371 of the update tarball. By default, a random 8-character ID will be
372 generated.
374 =back
376 =head1 BUGS
378 Please report bugs to <PACKAGE_BUGREPORT>.
380 =head1 SEE ALSO
382 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
384 =head1 COPYRIGHT
386 Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>.
388 This is free software and documentation. You can redistribute and/or modify it
389 under the terms of the GNU General Public License, version 2.
391 =cut