Update copyright information.
[ksplice.git] / ksplice-create.in
blobbe69374c64682b053ce29ba170f53762938005a1
1 #!/usr/bin/perl
3 # Copyright (C) 2007-2008 Ksplice, Inc.
4 # Authors: Jeff Arnold, Anders Kaseorg, Tim Abbott
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License, version 2.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
17 # 02110-1301, USA.
19 use strict;
20 use warnings;
21 use lib 'KSPLICE_DATA_DIR';
22 use Ksplice;
24 my ($patchfile, $diffext, $orig_config_dir, $jobs, $kid);
25 my $description;
26 my $series = 0;
27 my $build_modules = 0;
28 my @only_targets;
29 my @extra_match;
30 my $standalone;
31 my ($prebuild, $skip_prebuild) = (0, 0);
32 my @patch_opt = "-p1";
33 GetOptions(@common_options,
34 "id=s" => \$kid,
35 "patch=s" => \$patchfile,
36 "description=s" => \$description,
37 "diffext=s" => \$diffext,
38 "prebuild" => \$prebuild,
39 "series!" => \$series,
40 "build-modules!" => \$build_modules,
41 "only-targets=s" => \@only_targets,
42 "extra-match=s" => \@extra_match,
43 "standalone!" => \$standalone,
44 "skip-prebuild" => \$skip_prebuild,
45 "jobs|j:i" => \$jobs,
46 "config=s" => \$orig_config_dir,
47 "patch-opt=s" => \@patch_opt) or pod2usage(1);
49 pod2usage(1) if($help || scalar(@ARGV) != 1);
50 my $actions = (defined $patchfile) + (defined $diffext) + ($prebuild);
51 pod2usage(1) if($actions != 1);
53 my ($linuxtree) = (abs_path($ARGV[0]));
55 if(!defined $orig_config_dir) {
56 $orig_config_dir = "$linuxtree/ksplice";
58 else {
59 $orig_config_dir = abs_path($orig_config_dir);
60 if($orig_config_dir =~ $linuxtree) {
61 die "Aborting: User-specified ORIG_CONFIG cannot be KERNEL_SOURCE or a subdirectory";
64 if(!defined $orig_config_dir || ! -d $orig_config_dir) {
65 die "Failed to find ORIG_CONFIG directory ($orig_config_dir)";
67 if(! -e "$orig_config_dir/System.map") {
68 die "Failed to find System.map file in ORIG_CONFIG directory";
71 my $kernel_headers_dir = "$orig_config_dir/build";
72 $kernel_headers_dir = $linuxtree unless(-d $kernel_headers_dir);
74 my @kbuild_flags = ();
75 if(-e "$orig_config_dir/flags") {
76 open(FLAGS, '<', "$orig_config_dir/flags") or die;
77 local $/;
78 @kbuild_flags = shellwords(scalar <FLAGS>);
79 close(FLAGS);
82 $ENV{KSPLICE_VERBOSE} = $Verbose::level;
83 $ENV{KSPLICE_CONFIG_DIR} = $orig_config_dir;
85 my @chars = ('a'..'z', 0..9);
86 $kid = join '', map { $chars[int(rand(36))] } 0..7 if(!defined $kid);
87 my $ksplice = "ksplice-$kid";
88 $ENV{KSPLICE_KID} = $kid;
90 # Some versions of Fedora have System.map files whose symbol addresses disagree
91 # with the running kernel by a constant address offset. Here, Ksplice notes the
92 # System.map address for printk so that it can later compare this address against
93 # the kernel's address for printk. This comparison helps Ksplice work around
94 # this Fedora problem, and this comparison also helps Ksplice detect whether
95 # the user has provided an incorrect System.map file.
96 my $map_printk = runstr("$datadir/ksplice-obj.pl", "system_map_lookup", "printk");
98 print "Starting kernel builds (this process might take a long time)...\n"
99 if($Verbose::level >= 0);
101 $patchfile = abs_path($patchfile) if(defined $patchfile);
103 my $origdir = getcwd();
104 chdir($linuxtree);
106 my @make = ("make", "-rR");
107 if(defined $jobs) {
108 push @make, "-j$jobs";
109 } elsif(defined $ENV{CONCURRENCY_LEVEL}) {
110 push @make, "-j$ENV{CONCURRENCY_LEVEL}";
113 if($Verbose::level >= 2) {
114 push @make, "V=1";
115 } elsif($Verbose::level < 0) {
116 push @make, "-s";
119 $ENV{PATH} = "$datadir:$ENV{PATH}";
120 my @make_ksplice = (@make, "-f", "$datadir/Makefile.ksplice", @kbuild_flags);
122 push(@make_ksplice, "KSPLICE_BUILD_MODULES=1") if ($build_modules);
123 if(-e "include/config/kernel.release") {
124 push(@make_ksplice, "-o", "include/config/kernel.release");
127 my @revert_flags = ("KSPLICE_MODE=revert");
128 push(@revert_flags, "KSPLICE_SERIES=y") if ($series);
130 sub revert_orig() {
131 for(split(/\0/, runstr(qw(find -name *.KSPLICE_presrc -print0)))) {
132 my ($file) = m/^(.*)\.KSPLICE_presrc$/;
133 if ($series) {
134 unlink($_);
135 } else {
136 rename($_, $file);
139 runval(@make_ksplice, @revert_flags);
141 revert_orig();
143 if(!$skip_prebuild) {
144 if(-e "$orig_config_dir/.config") {
145 copy("$orig_config_dir/.config", "$linuxtree/.config");
146 utime((stat("$orig_config_dir/.config"))[8, 9],
147 "$linuxtree/.config");
149 my @snap_flags = ("KSPLICE_MODE=snap");
150 runval_raw(@make_ksplice, @snap_flags) == 0 or
151 die "Aborting: Prebuild failed";
152 sleep(1);
154 exit(0) if($prebuild);
156 my $tmpdir = tempdir('ksplice-tmp-XXXXXX', TMPDIR => 1, CLEANUP => 1);
157 copy($patchfile, "$tmpdir/patch") if(defined $patchfile);
158 $patchfile = "$tmpdir/patch";
160 if(defined $diffext) {
161 open(PATCH, '>', $patchfile) or die;
162 for(split(/\0/, runstr("find", "-name", "*$diffext", "-print0"))) {
163 my ($file) = /^(.*)\Q$diffext\E/ or die;
164 print PATCH runstr("diff", "-u", "--", $file, $_);
166 close(PATCH) or die;
167 @patch_opt = ("-p0");
170 my $kmodsrc = "$tmpdir/kmodsrc";
171 runval("cp", "-a", "--", "$datadir/kmodsrc", $kmodsrc);
172 $ENV{KSPLICE_KMODSRC} = $kmodsrc;
174 my @make_kmodsrc = (@make, "-C", $kernel_headers_dir, "M=$kmodsrc", "KSPLICE_KID=$kid", "KSPLICE_VERSION=PACKAGE_VERSION", "map_printk=$map_printk");
176 if (!defined($standalone)) {
177 $standalone = (runval_raw(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
179 push(@make_kmodsrc, "KSPLICE_STANDALONE=1") if ($standalone);
181 runval(@make_kmodsrc);
183 @patch_opt = ("-s", @patch_opt) if ($Verbose::level < 0);
185 runval_infile($patchfile, "patch", @patch_opt, "-bz", ".KSPLICE_presrc");
186 my @diff_flags = ("KSPLICE_MODE=diff");
187 push @diff_flags, "KSPLICE_EXTRA_MATCH=@extra_match" if (@extra_match);
188 push @diff_flags, "KSPLICE_ONLY_TARGETS=@only_targets" if (@only_targets);
189 if(runval_raw(@make_ksplice, @diff_flags) != 0) {
190 revert_orig() if(defined($diffext));
191 die "Aborting: Applying the patch appears to break the kernel build";
194 sub copy_debug {
195 my ($file) = @_;
196 my ($dir, $base) = (dirname($file), basename($file));
197 -d "$tmpdir/objects/$dir" or mkpath("$tmpdir/objects/$dir");
198 copy($file, "$tmpdir/objects/$file");
199 my $cmdfile = "$dir/.$base.cmd";
200 copy($cmdfile, "$tmpdir/objects/$cmdfile") if(-e $cmdfile);
203 mkdir("$tmpdir/objects");
204 for (split(/\0/, runstr(qw(find -name *.KSPLICE* ! ( -name *.KSPLICE -empty ) ! -name .*.KSPLICE.cmd -print0)))) {
205 next if (basename($_) =~ m/^(?:vmlinux|vmlinux\.o|\.tmp_vmlinux[0-9]+|\.tmp_kallsyms[0-9]+.o)\.KSPLICE_pre$/);
206 copy_debug($_);
207 copy_debug($1) if (m/^(.*)\.KSPLICE_pre(?:src)$/);
210 my @modulepaths = ();
211 my @modules = ();
212 foreach(glob("$kmodsrc/*.mod.KSPLICE")) {
213 open MOD, '<', $_;
214 chomp(my $mod = <MOD>);
215 close MOD;
216 push @modulepaths, "$mod.ko" if (basename($mod) ne "vmlinux");
217 push @modules, basename($mod);
220 if(!@modules) {
221 revert_orig() if(defined($diffext));
222 print STDERR "No changes detected.\n";
223 exit(66);
226 if ($build_modules) {
227 mkdir("$tmpdir/modules");
228 runval(@make_ksplice, "KSPLICE_MODE=modinst", "MODLIB=$tmpdir/modules", "INSTALL_MOD_STRIP=1", "modules=@modulepaths");
231 revert_orig() if(defined($diffext));
233 runval(@make_kmodsrc, "modules", "KSPLICE_MODULES=@modules");
234 runval(@make_kmodsrc, qw(modules_install --old-file=_modinst_post --old-file=_emodinst_post INSTALL_MOD_STRIP=1), "MODLIB=$tmpdir/ksplice-modules", "KSPLICE_MODULES=@modules");
236 chdir($tmpdir);
237 mkdir($ksplice);
238 move($patchfile, $ksplice);
239 if ($description) {
240 write_file("$ksplice/description", "$description\n");
242 write_file("$ksplice/api-version", "KSPLICE_API_VERSION\n");
243 write_file("$ksplice/timestamp", time() . "\n");
244 runval_outfile("$ksplice/utsname", "/usr/local/libexec/ksplice-kernel-utsname", "$kmodsrc/offsets.o");
245 open(CONTENTS, ">", "$ksplice/contents");
246 foreach my $mod (@modules) {
247 (my $target = $mod) =~ s/-/_/g;
248 my $mid = "${kid}_$target";
249 my $module = "ksplice-$mid";
250 rename("$tmpdir/ksplice-modules/extra/$module.ko", "$ksplice/$module.ko");
251 print CONTENTS "primary $target ksplice_$mid $module.ko\n";
252 rename("$tmpdir/ksplice-modules/extra/$module-helper.ko", "$ksplice/$module-helper.ko");
253 print CONTENTS "helper $target ksplice_$mid $module-helper.ko\n";
255 if ($standalone) {
256 rename("$tmpdir/ksplice-modules/extra/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko");
257 print CONTENTS "core ksplice_$kid ksplice-$kid.ko\n";
259 if ($build_modules) {
260 foreach my $mod (@modulepaths) {
261 (my $target = basename($mod)) =~ s/-/_/g;
262 print CONTENTS "target $target $mod\n";
266 mkdir("$ksplice/debug");
267 rename("objects", "$ksplice/debug/objects");
268 rename("modules", "$ksplice/modules") if ($build_modules);
269 rename("$kmodsrc", "$ksplice/debug/kmodsrc");
271 close(CONTENTS);
272 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
273 copy("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
274 print "Ksplice update tarball written to $ksplice.tar.gz\n";
275 exit(0);
277 =head1 NAME
279 ksplice-create - Create a set of kernel modules for a rebootless kernel update
281 =head1 SYNOPSIS
283 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
285 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
287 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
289 =head1 DESCRIPTION
291 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
292 will apply a user-specified source code patch to the running binary kernel.
294 Before you use B<ksplice-create> on a patch, you should confirm that the
295 desired source code change does not make any semantic changes to kernel data
296 structures--that is, changes that would require existing instances of kernel
297 data structures to be transformed (e.g., a patch that adds a field to a global
298 data structure would require the existing data structures to change). If you
299 use Ksplice on a patch that changes data structure semantics, Ksplice will not
300 detect the problem and you could experience kernel problems as a result.
302 The to-be-applied source code patch can be specified by providing a L<patch(1)>
303 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
304 (B<--diffext=>I<EXTENSION>).
306 If a file extension is specified, then the desired source code patch will be
307 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
308 whose names end with the extra extension I<EXTENSION> against the corresponding
309 files without the extra extension. Only the new files containing the extra
310 extension in their filenames should be modified.
312 Here is an example of using a file extension to specify a patch:
314 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
315 [edit sys.c.prctl_fixed to include the desired changes]
316 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
318 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
319 original source code. If your Linux distribution applies patches to the Linux
320 kernel during the kernel build process, then those patches must be applied to
321 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
322 directory. B<ksplice-create> will not modify the source code in the
323 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
324 directory tree.
326 I<ORIG_CONFIG> can be used to specify the directory containing the
327 to-be-updated kernel's original F<.config> file and original F<System.map> file
328 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
329 I<KERNEL_SOURCE>B</ksplice>.
331 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
332 close to the compiler and assembler originally used to build the running kernel
333 as possible. If the current compiler and linker are too different from the
334 original compiler and linker, B<ksplice-apply> will abort when applying the
335 update.
337 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
338 containing the desired Ksplice update modules. This tarball will be created in
339 the current directory, and it can be manipulated using the other Ksplice
340 utilities, such as B<ksplice-apply>.
342 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
343 directory, it must build that kernel from scratch, which is much slower than
344 the rest of the update-creation process. B<--prebuild> can be used to perform
345 this initial kernel build without providing a source code patch.
347 In order to patch a function that has previously been patched by Ksplice, the
348 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
349 contains the source for the currently running kernel, including any patches
350 that have previously been applied by Ksplice.
352 =head1 OPTIONS
354 =over 8
356 =item B<-v>, B<--verbose>
358 Causes B<ksplice-create> to print debugging messages about its progress. Using
359 multiple -v options increases the verbosity. The maximum is 2.
361 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
363 Specifies the number of jobs to run simultaneously while performing kernel
364 builds. B<ksplice-create> also honors the environment variable
365 CONCURRENCY_LEVEL.
367 =item B<--patch-opt=>I<OPTIONS>
369 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
370 B<-p1> is passed to B<patch>. If this option is specified, then only the
371 specified options will be passed to B<patch>. This option can be repeated in
372 order to pass multiple options to B<patch>. This option is ignored when the
373 to-be-applied source code patch is specified using B<--diffext>.
375 =item B<--id=>I<ID>
377 Specifies the unique value that will be used as the identifier of the
378 Ksplice update. This identifier will, for example, appear in the name
379 of the update tarball. By default, a random 8-character ID will be
380 generated.
382 =back
384 =head1 SEE ALSO
386 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
388 =head1 BUGS
390 Please report bugs to <PACKAGE_BUGREPORT>.
392 =head1 AUTHORS
394 Jeff Arnold, Anders Kaseorg, and Tim Abbott
396 =head1 COPYRIGHT
398 Copyright (C) 2007-2008 Ksplice, Inc.
400 This is free software and documentation. You can redistribute and/or modify it
401 under the terms of the GNU General Public License, version 2.
403 =cut