Define the common Getopt options in Ksplice.pm.
[ksplice.git] / ksplice-create.in
blobb96ff9f2c7c4eaea2ca73c116b3a17c06fbf1632
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 < 1) {
98 print "For output during this process, run ksplice-create with the option -v\n";
101 $patchfile = abs_path($patchfile) if(defined $patchfile);
103 my $origdir = getcwd();
104 chdir($linuxtree);
106 my @jlevel = (defined $ENV{CONCURRENCY_LEVEL} ? ("-j$ENV{CONCURRENCY_LEVEL}") : ());
107 @jlevel = ("-j$jobs") if(defined $jobs);
108 my @make_ksplice = ("make", "-f", "$datadir/Makefile.ksplice", "-rR", @jlevel, @kbuild_flags);
110 sub revert_orig() {
111 for(split(/\0/, runstr(qw(find -name *.KSPLICE* -print0)))) {
112 if(my ($file) = m/^(.*)\.KSPLICE_pre$/) {
113 rename($_, $file);
114 runval("$datadir/ksplice-obj.pl", "snap", "$file.KSPLICE") if(-e "$file.KSPLICE");
115 } elsif(m/\.KSPLICE_(?:primary|helper)$/) {
116 unlink($_) if(-e $_);
120 revert_orig();
122 if(!$skip_prebuild) {
123 copy("$orig_config_dir/.config", "$linuxtree/.config");
124 utime((stat("$orig_config_dir/.config"))[8, 9], "$linuxtree/.config");
125 my @snap_flags = ("KSPLICE_MODE=snap");
126 if(-e "include/config/kernel.release") {
127 push(@snap_flags, "-o", "include/config/kernel.release");
129 runval_raw(@make_ksplice, @snap_flags) == 0 or
130 die "Aborting: Prebuild failed";
131 sleep(1);
133 exit(0) if($prebuild);
135 my $tmpdir = tempdir('ksplice-tmp-XXXXXX', TMPDIR => 1, CLEANUP => 1);
136 copy($patchfile, "$tmpdir/patch") if(defined $patchfile);
137 $patchfile = "$tmpdir/patch";
139 if(defined $diffext) {
140 open(PATCH, '>', $patchfile) or die;
141 for(split(/\0/, runstr("find", "-name", "*$diffext", "-print0"))) {
142 my ($file) = /^(.*)\Q$diffext\E/ or die;
143 print PATCH runstr("diff", "-u", "--", $file, $_);
145 close(PATCH) or die;
146 @patch_opt = ("-p0");
149 my $kmodsrc = "$tmpdir/kmodsrc";
150 runval("cp", "-a", "--", "$datadir/kmodsrc", $kmodsrc);
151 $ENV{KSPLICE_KMODSRC} = $kmodsrc;
153 my @make_kmodsrc = ("make", "-C", $kernel_headers_dir, "M=$kmodsrc", "-rR", @jlevel, "KSPLICE_KID=$kid", "KSPLICE_VERSION=PACKAGE_VERSION", "map_printk=$map_printk");
155 if (!defined($standalone)) {
156 $standalone = (runval_raw(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
158 push(@make_kmodsrc, "KSPLICE_STANDALONE=1") if ($standalone);
160 runval(@make_kmodsrc);
162 runval_infile($patchfile, "patch", @patch_opt, "-bz", ".KSPLICE_pre");
163 push @make_ksplice, "KSPLICE_EXTRA_MATCH=@extra_match" if (@extra_match);
164 push @make_ksplice, "KSPLICE_ONLY_TARGETS=@only_targets" if (@only_targets);
165 if(runval_raw(@make_ksplice, "KSPLICE_MODE=diff") != 0) {
166 revert_orig();
167 die "Aborting: Applying the patch appears to break the kernel build";
170 sub copy_debug {
171 my ($file) = @_;
172 my ($dir, $base) = (dirname($file), basename($file));
173 -d "$tmpdir/objects/$dir" or mkpath("$tmpdir/objects/$dir");
174 copy($file, "$tmpdir/objects/$file");
175 my $cmdfile = "$dir/.$base.cmd";
176 copy($cmdfile, "$tmpdir/objects/$cmdfile") if(-e $cmdfile);
179 mkdir("$tmpdir/objects");
180 for (split(/\0/, runstr(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name .*.KSPLICE.cmd -print0)))) {
181 copy_debug($_);
182 copy_debug($1) if (m/^(.*)\.KSPLICE_pre$/);
185 my @modules = ();
186 foreach(glob(".tmp_versions/*.mod.KSPLICE")) {
187 open MOD, '<', $_;
188 chomp(my $mod = <MOD>);
189 close MOD;
190 foreach my $collect ("$mod.o.KSPLICE", "$mod.o.KSPLICE_primary",
191 "$mod.o.KSPLICE_helper") {
192 copy($collect, "$kmodsrc/" . basename($collect));
194 push @modules, basename($mod);
197 if(!@modules) {
198 revert_orig();
199 die "Aborting: No changes detected";
202 revert_orig();
204 runval(@make_kmodsrc, "modules", "KSPLICE_MODULES=@modules");
206 chdir($tmpdir);
207 mkdir($ksplice);
208 move($patchfile, $ksplice);
209 foreach my $mod (@modules) {
210 (my $target = $mod) =~ s/-/_/g;
211 my $mid = "${kid}_$target";
212 my $module = "ksplice-$mid";
213 rename("$kmodsrc/$module.ko", "$ksplice/$module.ko");
214 rename("$kmodsrc/$module-helper.ko", "$ksplice/$module-helper.ko");
216 rename("$kmodsrc/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko") if ($standalone);
218 mkdir("$ksplice/debug");
219 rename("objects", "$ksplice/debug/objects");
220 rename("$kmodsrc", "$ksplice/debug/kmodsrc");
221 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
222 copy("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
224 print "Ksplice update tarball written to $ksplice.tar.gz\n";
225 exit(0);
227 =head1 NAME
229 ksplice-create - Create a set of kernel modules for a rebootless kernel update
231 =head1 SYNOPSIS
233 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
235 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
237 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
239 =head1 DESCRIPTION
241 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
242 will apply a user-specified source code patch to the running binary kernel.
244 Before you use B<ksplice-create> on a patch, you should confirm that the
245 desired source code change does not make any semantic changes to kernel data
246 structures--that is, changes that would require existing instances of kernel
247 data structures to be transformed (e.g., a patch that adds a field to a global
248 data structure would require the existing data structures to change). If you
249 use Ksplice on a patch that changes data structure semantics, Ksplice will not
250 detect the problem and you could experience kernel problems as a result.
252 The to-be-applied source code patch can be specified by providing a L<patch(1)>
253 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
254 (B<--diffext=>I<EXTENSION>).
256 If a file extension is specified, then the desired source code patch will be
257 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
258 whose names end with the extra extension I<EXTENSION> against the corresponding
259 files without the extra extension. Only the new files containing the extra
260 extension in their filenames should be modified.
262 Here is an example of using a file extension to specify a patch:
264 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
265 [edit sys.c.prctl_fixed to include the desired changes]
266 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
268 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
269 original source code. If your Linux distribution applies patches to the Linux
270 kernel during the kernel build process, then those patches must be applied to
271 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
272 directory. B<ksplice-create> will not modify the source code in the
273 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
274 directory tree.
276 I<ORIG_CONFIG> can be used to specify the directory containing the
277 to-be-updated kernel's original F<.config> file and original F<System.map> file
278 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
279 I<KERNEL_SOURCE>B</ksplice>.
281 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
282 close to the compiler and assembler originally used to build the running kernel
283 as possible. If the current compiler and linker are too different from the
284 original compiler and linker, B<ksplice-apply> will abort when applying the
285 update.
287 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
288 containing the desired Ksplice update modules. This tarball will be created in
289 the current directory, and it can be manipulated using the other Ksplice
290 utilities, such as B<ksplice-apply>.
292 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
293 directory, it must build that kernel from scratch, which is much slower than
294 the rest of the update-creation process. B<--prebuild> can be used to perform
295 this initial kernel build without providing a source code patch.
297 In order to patch a function that has previously been patched by Ksplice, the
298 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
299 contains the source for the currently running kernel, including any patches
300 that have previously been applied by Ksplice.
302 =head1 OPTIONS
304 =over 8
306 =item B<-v>, B<--verbose>
308 Causes B<ksplice-create> to print debugging messages about its progress. Using
309 multiple -v options increases the verbosity. The maximum is 2.
311 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
313 Specifies the number of jobs to run simultaneously while performing kernel
314 builds. B<ksplice-create> also honors the environment variable
315 CONCURRENCY_LEVEL.
317 =item B<--patch-opt=>I<OPTIONS>
319 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
320 B<-p1> is passed to B<patch>. If this option is specified, then only the
321 specified options will be passed to B<patch>. This option can be repeated in
322 order to pass multiple options to B<patch>. This option is ignored when the
323 to-be-applied source code patch is specified using B<--diffext>.
325 =item B<--id=>I<ID>
327 Specifies the unique value that will be used as the identifier of the
328 Ksplice update. This identifier will, for example, appear in the name
329 of the update tarball. By default, a random 8-character ID will be
330 generated.
332 =back
334 =head1 BUGS
336 Please report bugs to <PACKAGE_BUGREPORT>.
338 =head1 SEE ALSO
340 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
342 =head1 COPYRIGHT
344 Copyright (C) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
345 Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
346 Tim Abbott <tabbott@mit.edu>
348 This is free software and documentation. You can redistribute and/or modify it
349 under the terms of the GNU General Public License, version 2.
351 =cut