Add a --id option to ksplice-create.
[ksplice.git] / ksplice-create.in
blob37ba6d7c2d762d95b0b5ad1fcb4852c2fe872dde
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 Pod::Usage;
21 use strict;
22 use warnings;
23 use lib 'KSPLICE_DATA_DIR';
24 use ksplice;
26 my ($patchfile, $diffext, $orig_config_dir, $postdir, $jobs, $kid);
27 my ($help, $wantversion, $prebuild, $skip_prebuild, $apply, $patch_opt) = (0, 0, 0, 0, 0, "-p1");
28 Getopt::Long::Configure("bundling");
29 GetOptions("help|?" => \$help,
30 "version" => \$wantversion,
31 "verbose|v!" => \$verbose,
32 "id=s" => \$kid,
33 "patch=s" => \$patchfile,
34 "diffext=s" => \$diffext,
35 "prebuild" => \$prebuild,
36 "skip-prebuild" => \$skip_prebuild,
37 "jobs|j:i" => \$jobs,
38 "config=s" => \$orig_config_dir,
39 "apply" => \$apply,
40 "postdir=s" => \$postdir,
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 = init_tmpdir();
54 runval("cp", "--", $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 $ENV{KSPLICE_CONFIG_DIR} = $orig_config_dir;
81 if(!defined $postdir) {
82 $postdir = "$orig_config_dir/post";
84 elsif($postdir =~ $linuxtree) {
85 die "Aborting: User-specified postdir cannot be KERNEL_SOURCE or a subdirectory";
88 runval("cp", "--", "$orig_config_dir/.config", $linuxtree);
90 my @chars = ('a'..'z', 0..9);
91 $kid = join '', map { $chars[int(rand(36))] } 0..7 if(!defined $kid);
92 my $ksplice = "ksplice-$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.pl", "system_map_lookup", "printk");
102 print "Starting kernel builds (this process might take a long time)...\n";
103 if(!$verbose) {
104 print "For output during this process, run ksplice-create with the option -v\n";
107 ###################################################################
108 # PHASE 1: Determine which object files are modified by the patch #
109 # - performs the pre and post kernel builds #
110 # - uses objdiff to identify which ELF sections have changed and #
111 # which ELF symbols are entry points to those sections #
112 ###################################################################
114 # We will refer to the object files modified by the patch as the "target object
115 # files", the ELF sections changed by the patch as the "target sections", and
116 # the entry points of those sections as the "target entry points".
118 my $origdir = getcwd();
119 runcd($linuxtree);
120 if(defined $diffext) {
121 runval("$libexecdir/ksplice-gendiff-reversed >$patchfile . $diffext");
124 my @jlevel = (defined $ENV{CONCURRENCY_LEVEL} ? ("-j$ENV{CONCURRENCY_LEVEL}") : ());
125 @jlevel = ("-j$jobs") if(defined $jobs);
126 my @make_ksplice = ("make", "-f", "$datadir/Makefile.ksplice", @jlevel);
128 sub revert_orig() {
129 for (split(/\0/, runstr(qw(find -name *.KSPLICE_pre -print0)))) {
130 s/\.KSPLICE_pre$//;
131 rename("$_.KSPLICE_pre", $_);
132 unlink("$_.KSPLICE") if(-e "$_.KSPLICE");
135 revert_orig();
137 if(!$skip_prebuild &&
138 runval_raw(@make_ksplice, "KSPLICE_MODE=snap") != 0) {
139 die "Aborting: Prebuild failed";
141 exit(0) if($prebuild);
142 runval("patch $patch_opt -bz .KSPLICE_pre < $patchfile");
143 if(runval_raw(@make_ksplice, "KSPLICE_MODE=diff") != 0) {
144 revert_orig();
145 die "Aborting: Applying the patch appears to break the kernel build";
148 runval("mkdir", "-p", "--", "$tmpdir/collect");
150 my @modules = ();
151 foreach(glob(".tmp_versions/*.mod.KSPLICE")) {
152 open MOD, '<', $_;
153 chomp(my $module = <MOD>);
154 close MOD;
155 runval("cp", "$module.o.KSPLICE", "$tmpdir/collect/");
156 runval("cp", "$module.o.KSPLICE_primary", "$tmpdir/collect/");
157 runval("cp", "$module.o.KSPLICE_helper", "$tmpdir/collect/");
158 $module =~ s/^.*\///;
159 push @modules, $module;
162 if(!@modules) {
163 revert_orig();
164 die "Aborting: No changes detected";
167 revert_orig();
169 for my $module (@modules) {
170 runcd("$tmpdir/collect");
172 ################################################################################
173 # PHASE 3: Combine the target object files and prepare for kernel module build #
174 # - links the many target object files into two "collection" object files #
175 # - saves the reloc info extracted earlier in ELF sect .ksplice.ksplice_relocs #
176 # - uses objmanip's sizelist mode to save the names and sizes of target funcs #
177 # - uses ld-script to aggregate all ELF text sections into .text #
178 # - saves the list of target entry syms in ELF sect .ksplice.ksplice_patches #
179 ################################################################################
181 runcd($tmpdir);
182 runval("cp", "-a", "--", "$datadir/kmodsrc", "kmodsrc-$module");
183 runval("mv", "collect/$module.o.KSPLICE_primary", "kmodsrc-$module/collection.o.primary");
184 runval("mv", "collect/$module.o.KSPLICE_helper", "kmodsrc-$module/collection.o.helper");
185 runcd("kmodsrc-$module");
187 runval("ld", "--script=ld-script", "-r", "-o", "collection.o.primary.postld", "collection.o.primary");
188 runval("cp", "collection.o.primary.postld", "collection.o.primary");
189 runval("ld", "--script=ld-script", "-r", "-o", "collection.o.helper.postld", "collection.o.helper");
190 runval("cp", "collection.o.helper.postld", "collection.o.helper");
192 ###############################################################################
193 # PHASE 4: Build the kernel modules and create the update tarball #
194 # - builds primary and helper kernel modules #
195 # - uses objmanip's rmsyms mode to remove relocations to non-exported symbols #
196 # - creates a tarball of the primary module and the helper module #
197 ###############################################################################
199 my $kid_m = "${kid}_$module";
200 $kid_m =~ s/-/_/g;
201 my $ksplice_m = "ksplice-$kid_m";
202 runval("make", @jlevel, "modules", "KSPLICE_ID=$kid_m", "KSPLICE_TARGET=$module", "map_printk=$map_printk", "KERNELSRC=$linuxtree");
205 runcd($tmpdir);
206 runval("mkdir", $ksplice);
207 runval("mv", "--", $patchfile, $ksplice);
208 for my $module (@modules) {
209 my $kid_m = "${kid}_$module";
210 $kid_m =~ s/-/_/g;
211 my $ksplice_m = "ksplice-$kid_m";
212 runval("mv", "--", "kmodsrc-$module/$ksplice_m.ko", "kmodsrc-$module/$ksplice_m-helper.ko", $ksplice);
214 runval("mkdir", "$ksplice/debug");
215 runval("mv", "collect", "$ksplice/debug");
216 for my $module (@modules) {
217 runval("mv", "kmodsrc-$module", "$ksplice/debug");
219 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
220 runval("cp", "--", "$ksplice.tar.gz", $origdir);
221 runcd($origdir);
222 runval("rm", "-rf", "--", "$tmpdir");
224 print "Ksplice update tarball written to $ksplice.tar.gz\n";
226 if($apply) {
227 print "Now running ksplice-apply to apply update...\n";
228 exec("ksplice-apply", $ksplice) || die;
231 exit(0);
233 =head1 NAME
235 ksplice-create - Create a set of kernel modules for a rebootless kernel update
237 =head1 SYNOPSIS
239 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
241 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
243 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
245 =head1 DESCRIPTION
247 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
248 will apply a user-specified source code patch to the running binary kernel.
250 Before you use B<ksplice-create> on a patch, you should confirm that the
251 desired source code change does not make any semantic changes to kernel data
252 structures--that is, changes that would require existing instances of kernel
253 data structures to be transformed (e.g., a patch that adds a field to a global
254 data structure would require the existing data structures to change). If you
255 use Ksplice on a patch that changes data structure semantics, Ksplice will not
256 detect the problem and you could experience kernel problems as a result.
258 The to-be-applied source code patch can be specified by providing a L<patch(1)>
259 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
260 (B<--diffext=>I<EXTENSION>).
262 If a file extension is specified, then the desired source code patch will be
263 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
264 whose names end with the extra extension I<EXTENSION> against the corresponding
265 files without the extra extension. Only the new files containing the extra
266 extension in their filenames should be modified.
268 Here is an example of using a file extension to specify a patch:
270 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
271 [edit sys.c.prctl_fixed to include the desired changes]
272 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
274 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
275 original source code. If your Linux distribution applies patches to the Linux
276 kernel during the kernel build process, then those patches must be applied to
277 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
278 directory. B<ksplice-create> will not modify the source code in the
279 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
280 directory tree.
282 I<ORIG_CONFIG> can be used to specify the directory containing the
283 to-be-updated kernel's original F<.config> file and original F<System.map> file
284 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
285 I<KERNEL_SOURCE>B</ksplice>.
287 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
288 close to the compiler and assembler originally used to build the running kernel
289 as possible. If the current compiler and linker are too different from the
290 original compiler and linker, B<ksplice-apply> will abort when applying the
291 update.
293 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
294 containing the desired Ksplice update modules. This tarball will be created in
295 the current directory, and it can be manipulated using the other Ksplice
296 utilities, such as B<ksplice-apply>.
298 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
299 directory, it must build that kernel from scratch, which is much slower than
300 the rest of the update-creation process. B<--prebuild> can be used to perform
301 this initial kernel build (and set up a tentative B<post> directory tree)
302 without providing a source code patch.
304 In order to patch a function that has previously been patched by Ksplice, the
305 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
306 contains the source for the currently running kernel, including any patches
307 that have previously been applied by Ksplice.
309 =head1 OPTIONS
311 =over 8
313 =item B<-v>, B<--verbose>
315 Prints the commands being executed, the output of the commands being executed,
316 and various other pieces of information.
318 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
320 Specifies the number of jobs to run simultaneously while performing kernel
321 builds. B<ksplice-create> also honors the environment variable
322 CONCURRENCY_LEVEL.
324 =item B<--apply>
326 Immediately applies the generated update to the running kernel by invoking
327 B<ksplice-apply>.
329 =item B<--postdir=>I<DIRECTORY>
331 Specifies a directory that is B<dedicated to Ksplice> to be used as the Ksplice
332 I<post> directory. Defaults to I<ORIG_CONFIG>B</post>. If this directory
333 exists, the directory's contents will be removed. If it does not exist, it
334 will be created.
336 =item B<--patch-opt=>I<OPTIONS>
338 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
339 B<-p1> is passed to B<patch>. If this option is specified, then only the
340 specified options will be passed to B<patch>. This option can be repeated in
341 order to pass multiple options to B<patch>. This option is ignored when the
342 to-be-applied source code patch is specified using B<--diffext>.
344 =item B<--id=>I<ID>
346 Specifies the unique value that will be used as the identifier of the
347 Ksplice update. This identifier will, for example, appear in the name
348 of the update tarball. By default, a random 8-character ID will be
349 generated.
351 =back
353 =head1 BUGS
355 Please report bugs to <PACKAGE_BUGREPORT>.
357 =head1 SEE ALSO
359 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
361 =head1 COPYRIGHT
363 Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>.
365 This is free software and documentation. You can redistribute and/or modify it
366 under the terms of the GNU General Public License, version 2.
368 =cut