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
20 use lib
'KSPLICE_DATA_DIR';
23 my ($patchfile, $diffext, $orig_config_dir, $jobs, $kid);
25 my ($help, $wantversion, $prebuild, $skip_prebuild, $apply, $patch_opt) = (0, 0, 0, 0, 0, "-p1");
26 GetOptions
("help|?" => \
$help,
27 "version" => \
$wantversion,
28 "verbose|v:+" => \
$Verbose::level
,
30 "patch=s" => \
$patchfile,
31 "diffext=s" => \
$diffext,
32 "prebuild" => \
$prebuild,
33 "standalone!" => \
$standalone,
34 "skip-prebuild" => \
$skip_prebuild,
36 "config=s" => \
$orig_config_dir,
38 "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 my $tmpdir = tempdir
('ksplice-tmp-XXXXXX', TMPDIR
=> 1, CLEANUP
=> 1);
51 copy
($patchfile, "$tmpdir/patch") if(defined $patchfile);
52 $patchfile = "$tmpdir/patch";
54 $patch_opt = "-p0" if(defined $diffext);
55 $patch_opt = join(" ", @
$patch_opt) if(ref $patch_opt);
57 if(!defined $orig_config_dir) {
58 $orig_config_dir = "$linuxtree/ksplice";
61 $orig_config_dir = abs_path
($orig_config_dir);
62 if($orig_config_dir =~ $linuxtree) {
63 die "Aborting: User-specified ORIG_CONFIG cannot be KERNEL_SOURCE or a subdirectory";
66 if(!defined $orig_config_dir || ! -d
$orig_config_dir) {
67 die "Failed to find ORIG_CONFIG directory ($orig_config_dir)";
69 if(! -e
"$orig_config_dir/.config") {
70 die "Failed to find .config file in ORIG_CONFIG directory";
72 if(! -e
"$orig_config_dir/System.map") {
73 die "Failed to find System.map file in ORIG_CONFIG directory";
76 my $kernel_headers_dir = "$orig_config_dir/build";
77 $kernel_headers_dir = $linuxtree unless(-d
$kernel_headers_dir);
79 my @kbuild_flags = ();
80 if(-e
"$orig_config_dir/flags") {
81 open(FLAGS
, '<', "$orig_config_dir/flags") or die;
83 @kbuild_flags = &shellwords
(<FLAGS
>);
87 $ENV{KSPLICE_VERBOSE
} = $Verbose::level
;
88 $ENV{KSPLICE_CONFIG_DIR
} = $orig_config_dir;
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-obj.pl", "system_map_lookup", "printk");
102 print "Starting kernel builds (this process might take a long time)...\n";
103 if($Verbose::level
< 1) {
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
();
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, @kbuild_flags);
129 for(split(/\0/, runstr
(qw(find -name *.KSPLICE*pre* -print0)))) {
130 if(my ($file) = m/^(.*)\.KSPLICE_pre$/) {
132 runval
("$datadir/ksplice-obj.pl", "snap", "$file.KSPLICE") if(-e
"$file.KSPLICE");
133 } elsif(m/\.KSPLICE.*\.pre/) {
140 if(!$skip_prebuild) {
141 copy
("$orig_config_dir/.config", "$linuxtree/.config");
142 runval_raw
(@make_ksplice, "KSPLICE_MODE=snap") == 0 or
143 die "Aborting: Prebuild failed";
145 exit(0) if($prebuild);
147 if (!defined($standalone)) {
148 $standalone = (runval_raw
(qw(grep -q ^CONFIG_KSPLICE=[ym]$), "$linuxtree/.config") != 0);
151 @standalone_flag = qw(KSPLICE_STANDALONE=1) if ($standalone);
153 runval
("patch $patch_opt -bz .KSPLICE_pre < $patchfile");
154 if(runval_raw
(@make_ksplice, "KSPLICE_MODE=diff") != 0) {
156 die "Aborting: Applying the patch appears to break the kernel build";
161 my ($dir, $base) = (dirname
($file), basename
($file));
162 -d
"$tmpdir/objects/$dir" or 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
)))) {
171 copy_debug
($1) if (m/^(.*)\.KSPLICE_pre$/);
174 runval
("cp", "-a", "--", "$datadir/kmodsrc", "$tmpdir/kmodsrc");
177 foreach(glob(".tmp_versions/*.mod.KSPLICE")) {
179 chomp(my $mod = <MOD
>);
181 foreach my $collect ("$mod.o.KSPLICE", "$mod.o.KSPLICE_primary",
182 "$mod.o.KSPLICE_helper") {
183 copy
($collect, "$tmpdir/kmodsrc/" . basename
($collect));
185 push @modules, basename
($mod);
190 die "Aborting: No changes detected";
195 runval
("make", "-C", $kernel_headers_dir, "M=$tmpdir/kmodsrc", @jlevel, "modules", "KSPLICE_KID=$kid", "KSPLICE_MODULES=@modules", "KSPLICE_VERSION=PACKAGE_VERSION", "map_printk=$map_printk", @standalone_flag);
199 move
($patchfile, $ksplice);
200 foreach my $mod (@modules) {
201 (my $target = $mod) =~ s/-/_/g;
202 my $mid = "${kid}_$target";
203 my $module = "ksplice-$mid";
204 rename("kmodsrc/$module.ko", "$ksplice/$module.ko");
205 rename("kmodsrc/$module-helper.ko", "$ksplice/$module-helper.ko");
207 rename("kmodsrc/ksplice-$kid.ko", "$ksplice/ksplice-$kid.ko") if ($standalone);
209 mkdir("$ksplice/debug");
210 rename("objects", "$ksplice/debug/objects");
211 rename("kmodsrc", "$ksplice/debug/kmodsrc");
212 runval
("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
213 copy
("$ksplice.tar.gz", "$origdir/$ksplice.tar.gz");
215 print "Ksplice update tarball written to $ksplice.tar.gz\n";
218 print "Now running ksplice-apply to apply update...\n";
219 exec("ksplice-apply", $ksplice) || die;
226 ksplice-create - Create a set of kernel modules for a rebootless kernel update
230 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
232 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
234 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
238 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
239 will apply a user-specified source code patch to the running binary kernel.
241 Before you use B<ksplice-create> on a patch, you should confirm that the
242 desired source code change does not make any semantic changes to kernel data
243 structures--that is, changes that would require existing instances of kernel
244 data structures to be transformed (e.g., a patch that adds a field to a global
245 data structure would require the existing data structures to change). If you
246 use Ksplice on a patch that changes data structure semantics, Ksplice will not
247 detect the problem and you could experience kernel problems as a result.
249 The to-be-applied source code patch can be specified by providing a L<patch(1)>
250 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
251 (B<--diffext=>I<EXTENSION>).
253 If a file extension is specified, then the desired source code patch will be
254 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
255 whose names end with the extra extension I<EXTENSION> against the corresponding
256 files without the extra extension. Only the new files containing the extra
257 extension in their filenames should be modified.
259 Here is an example of using a file extension to specify a patch:
261 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
262 [edit sys.c.prctl_fixed to include the desired changes]
263 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
265 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
266 original source code. If your Linux distribution applies patches to the Linux
267 kernel during the kernel build process, then those patches must be applied to
268 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
269 directory. B<ksplice-create> will not modify the source code in the
270 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
273 I<ORIG_CONFIG> can be used to specify the directory containing the
274 to-be-updated kernel's original F<.config> file and original F<System.map> file
275 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
276 I<KERNEL_SOURCE>B</ksplice>.
278 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
279 close to the compiler and assembler originally used to build the running kernel
280 as possible. If the current compiler and linker are too different from the
281 original compiler and linker, B<ksplice-apply> will abort when applying the
284 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
285 containing the desired Ksplice update modules. This tarball will be created in
286 the current directory, and it can be manipulated using the other Ksplice
287 utilities, such as B<ksplice-apply>.
289 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
290 directory, it must build that kernel from scratch, which is much slower than
291 the rest of the update-creation process. B<--prebuild> can be used to perform
292 this initial kernel build without providing a source code patch.
294 In order to patch a function that has previously been patched by Ksplice, the
295 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
296 contains the source for the currently running kernel, including any patches
297 that have previously been applied by Ksplice.
303 =item B<-v>, B<--verbose>
305 Causes B<ksplice-create> to print debugging messages about its progress. Using
306 multiple -v options increases the verbosity. The maximum is 2.
308 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
310 Specifies the number of jobs to run simultaneously while performing kernel
311 builds. B<ksplice-create> also honors the environment variable
316 Immediately applies the generated update to the running kernel by invoking
319 =item B<--patch-opt=>I<OPTIONS>
321 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
322 B<-p1> is passed to B<patch>. If this option is specified, then only the
323 specified options will be passed to B<patch>. This option can be repeated in
324 order to pass multiple options to B<patch>. This option is ignored when the
325 to-be-applied source code patch is specified using B<--diffext>.
329 Specifies the unique value that will be used as the identifier of the
330 Ksplice update. This identifier will, for example, appear in the name
331 of the update tarball. By default, a random 8-character ID will be
338 Please report bugs to <PACKAGE_BUGREPORT>.
342 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
346 Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@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.