Ksplice 0.9.4
[ksplice.git] / ksplice-apply.in
blob2a84e5551365f80b8cb8be62be478d59084f4815
1 #!/usr/bin/perl
3 # Copyright (C) 2007-2008 Jeff 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 $debug;
26 my $debugon = 0;
27 my $partial = 0;
28 GetOptions(@common_options,
29 "partial" => \$partial,
30 "debug" => \$debugon,
31 "debugfile=s" => \$debug) or pod2usage(1);
33 pod2usage(1) if($help || scalar(@ARGV) != 1);
35 my $file = abs_path($ARGV[0]);
36 $debugon = 1 if(defined $debug);
37 $debug = abs_path($debug) if (defined $debug);
39 my $tmpdir = tempdir('ksplice-tmp-XXXXXX', TMPDIR => 1, CLEANUP => 1);
40 chdir($tmpdir);
41 my $ksplice = unpack_update($file);
42 chdir($ksplice);
44 die "No contents file in $file\n" if (!-e "contents");
45 open(CONTENTS, '<', "contents");
46 my $core;
47 while (<CONTENTS>) {
48 my @line = split(' ', $_);
49 if ($line[0] eq 'core') {
50 die "Multiple core modules in $file!" if (defined $core);
51 $core = {
52 module => $line[1],
53 file => $line[2],
57 close(CONTENTS);
59 my $nounload = runstr("lsmod") =~ m/- $/m;
61 (my $kid = $ksplice) =~s|ksplice[-_]([^-_]+)|$1|;
62 my $update = "ksplice_$kid";
63 if(update_loaded($kid)) {
64 my $stage = get_stage($kid);
65 if ($stage eq "applied") {
66 print STDERR "Ksplice update $kid already applied.\n";
67 exit(0);
69 die "Reversed Ksplice module $update already loaded!" if ($stage eq "reversed");
72 runstr_err(qw(modprobe -q ksplice)) eq "" || die;
73 if (defined $core) {
74 die "Could not find Ksplice core module $core->{file}\n" if (!-e $core->{file});
75 if (runstr("lsmod") =~ m/^\Q$core->{module}\E\s+/) {
76 die "Ksplice core module $core already loaded.";
78 if (!load_module($core->{file}, "debug=$debugon")) {
79 die "Error loading Ksplice core module $core->{module} for update $kid";
83 my @helpers = ();
84 foreach my $helper (glob('ksplice-*-helper.ko')) {
85 (my $primary = $helper) =~ s/\-helper\.ko$/.ko/;
86 die unless(-e $primary && -e $helper);
87 (my $target = $primary) =~ s/^ksplice-[^_]+_(.*)\.ko/$1/;
88 if ($target ne 'vmlinux' && runstr("lsmod") !~ m/^${target}\s/m) {
89 if (!$partial) {
90 cleanup_modules();
91 print_error("target_not_loaded");
92 die "Module $target to be patched not loaded";
95 push @helpers, $helper;
97 foreach my $helper (@helpers) {
98 (my $primary = $helper) =~ s/\-helper\.ko$/.ko/;
99 if(!load_module($primary)) {
100 die "Error loading primary module $primary";
102 if(!load_module($helper)) {
103 my $debugfile = get_debug_output("init_$kid", $debug);
104 print STDERR "Error loading helper module $helper\n";
105 (my $module = $primary) =~ s/-/_/g;
106 $module =~ s/\.ko//;
107 cleanup_modules();
108 if($debugon && defined $debugfile) {
109 print("Debugging output saved to $debugfile\n");
111 die;
115 set_debug_level($kid, $debugon);
116 set_partial($kid, $partial);
117 set_stage($kid, "applied");
118 my $stage = get_stage($kid);
119 if($stage ne 'applied') {
120 my $debugfile = get_debug_output($kid, $debug);
121 my $abort_cause = get_abort_cause($kid);
122 my $conflicts = get_conflicts($kid);
123 cleanup_modules();
124 print STDERR "Error applying Ksplice update $kid:\n";
125 print_error($abort_cause);
126 if ($abort_cause eq 'code_busy') {
127 print $conflicts;
129 if ($debugon && defined $debugfile) {
130 print("Debugging output saved to $debugfile\n");
132 die;
134 mkpath("/var/run/ksplice/updates/$kid");
135 copy("patch", "/var/run/ksplice/updates/$kid/patch") if (-e "patch");
136 copy("description", "/var/run/ksplice/updates/$kid/description") if (-e "description");
137 if (!$nounload) {
138 foreach my $helper (@helpers) {
139 $helper =~ s/-/_/g;
140 $helper =~ s/\.ko$//;
141 (my $primary = $helper) =~ s/_helper$//;
142 runval('rmmod', $helper);
143 runval('rmmod', $primary) if ($partial && refcount($primary) == 0);
146 print "Done!\n";
147 exit(0);
149 my @modules_loaded = qw();
151 sub load_module {
152 my ($module, @params) = @_;
153 if (runval_raw("insmod", $module, @params) != 0) {
154 child_error();
155 return 0;
157 $module =~ s/\.ko//;
158 $module =~ s/-/_/g;
159 push @modules_loaded, $module;
160 return 1;
163 sub refcount {
164 my ($module) = @_;
165 foreach(split(/\n/, runstr("lsmod"))) {
166 if (m/^(\S+)\s+[0-9]+\s+([0-9])+\s/) {
167 return $2 if ($1 eq $module);
170 return -1;
173 sub cleanup_modules {
174 foreach my $module (reverse(@modules_loaded)) {
175 runval("rmmod", $module) if(!$nounload);
179 sub print_error {
180 my ($error) = @_;
181 my %errors = (
182 "no_match" => <<'END',
183 Ksplice has aborted the upgrade because Ksplice has been unable to match the
184 object code produced by your current compiler and assembler against the running
185 kernel's object code. If you provided the exact kernel source to the running
186 kernel, then it appears that your current compiler and/or assembler are
187 behaving differently from the compiler and assembler used to build the running
188 kernel. If possible, please use the exact compiler and assembler that were
189 used to build the running kernel. If you are using exactly the same compiler
190 and assembler, consider reporting a bug to PACKAGE_BUGREPORT.
192 "code_busy" => <<'END',
193 Ksplice has aborted the upgrade because it appears that the code that you are
194 trying to patch is continuously in use by the system. More specifically,
195 Ksplice has been unable to find a moment when one or more of the to-be-patched
196 functions is not on a thread's kernel stack.
198 "bad_system_map" => <<'END',
199 Ksplice has aborted the upgrade because it appears that the System.map file
200 provided to ksplice-create does not match the running kernel.
202 "failed_to_find" => <<'END',
203 Ksplice has aborted the upgrade because it was unable to resolve some of the
204 symbols used in the update.
206 "already_reversed" => <<'END',
207 The Ksplice update that you are attempting to apply has already been applied
208 and reversed. You need to unload the Ksplice modules associated with this
209 update before you can apply this update again.
211 "missing_export" => <<'END',
212 Ksplice has aborted the upgrade because the symbols exported by the kernel
213 did not match Ksplice's expectations.
215 "unexpected_running_task" => <<'END',
216 Ksplice has aborted the upgrade because of an unexpected failure during the
217 kernel stack check. Please consider reporting a bug to PACKAGE_BUGREPORT.
219 "target_not_loaded" => <<'END',
220 Ksplice has aborted the upgrade because one of the modules to be
221 patched by the update was not loaded. If you want to apply this
222 update only to those modules that are loaded, then you should use the
223 --partial option.
225 "out_of_memory" => <<'END',
226 Ksplice has aborted the upgrade because the kernel ran out of memory.
228 "call_failed" => <<'END',
229 Ksplice has aborted the upgrade at the request of a one of the
230 pre-application hooks that were included as part of this Ksplice
231 update. This is likely the result of a bug in the patch used to
232 generate this update.
234 "unexpected" => <<'END',
235 Ksplice has aborted because of an unexpected error.
236 Please consider reporting a bug to PACKAGE_BUGREPORT.
238 "UNKNOWN" => <<'END',
239 The Ksplice kernel component has returned an error code that this version of
240 ksplice-apply does not understand.
242 "ok" => <<'END',
243 Ksplice has aborted the upgrade for unknown reasons.
244 Please consider reporting a bug to PACKAGE_BUGREPORT.
247 $error = "UNKNOWN" if (!exists $errors{$error});
248 print STDERR "\n$errors{$error}\n";
251 =head1 NAME
253 ksplice-apply - Apply an on-disk Ksplice update to the running kernel
255 =head1 SYNOPSIS
257 B<ksplice-apply> I<UPDATE_TARBALL>
259 =head1 DESCRIPTION
261 B<ksplice-apply> takes as input a Ksplice update tarball, as generated by
262 L<ksplice-create(8)>, and it applies the update to the running binary kernel.
264 The update tarball used with B<ksplice-apply> must have been generated for the
265 running kernel's version.
267 =head1 OPTIONS
269 =over 8
271 =item B<--debug>
273 Applies the update with debugging output enabled. Recommended only for
274 debugging.
276 =item B<--debugfile=>I<filename>
278 Sets the location where debugging output should be saved. Implies --debug.
280 =item B<--partial>
282 Applies the update only to those modules which are loaded. Any
283 modules patched by the update that are not loaded are ignored (without
284 this option, Ksplice aborts if any modules patched by the update are
285 not loaded).
287 =back
289 =head1 SEE ALSO
291 L<ksplice-create(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
293 =head1 BUGS
295 Please report bugs to <PACKAGE_BUGREPORT>.
297 =head1 COPYRIGHT
299 Copyright (C) 2007-2008 Jeff Arnold <jbarnold@mit.edu>
301 Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
302 Tim Abbott <tabbott@mit.edu>
304 This is free software and documentation. You can redistribute and/or modify it
305 under the terms of the GNU General Public License, version 2.
307 =cut