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
22 use lib
'KSPLICE_DATA_DIR';
25 my ($patchfile, $diffext, $orig_config_dir, $jobs, $kid);
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
,
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,
40 "config=s" => \
$orig_config_dir,
41 "patch-opt=s@" => \
$patch_opt) or pod2usage
(1);
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";
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;
86 @kbuild_flags = shellwords
(scalar <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
();
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);
122 for(split(/\0/, runstr
(qw(find -name *.KSPLICE*pre* -print0)))) {
123 if(my ($file) = m/^(.*)\.KSPLICE_pre$/) {
125 runval
("$datadir/ksplice-obj.pl", "snap", "$file.KSPLICE") if(-e
"$file.KSPLICE");
126 } elsif(m/\.KSPLICE.*\.pre/) {
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";
144 exit(0) if($prebuild);
146 if (!defined($standalone)) {
147 $standalone = (runval_raw
(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
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) {
155 die "Aborting: Applying the patch appears to break the kernel build";
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
)))) {
170 copy_debug
($1) if (m/^(.*)\.KSPLICE_pre$/);
173 runval
("cp", "-a", "--", "$datadir/kmodsrc", "$tmpdir/kmodsrc");
176 foreach(glob(".tmp_versions/*.mod.KSPLICE")) {
178 chomp(my $mod = <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);
189 die "Aborting: No changes detected";
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);
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";
219 ksplice-create - Create a set of kernel modules for a rebootless kernel update
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>
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
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
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.
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
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>.
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
326 Please report bugs to <PACKAGE_BUGREPORT>.
330 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
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.